From 489de09a8130d70f095b39f14afdb1e925b83bf3 Mon Sep 17 00:00:00 2001 From: antonio teran Date: Fri, 20 Dec 2019 09:23:49 -0800 Subject: [PATCH 01/57] Initial extraction of analysis tools and fuctions for Bayes tree. --- src/AnalysisTools.jl | 85 +++++++++++++++++++++++++++++++++++++++ test/testAnalysisTools.jl | 23 +++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/AnalysisTools.jl create mode 100644 test/testAnalysisTools.jl diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl new file mode 100644 index 000000000..aea7643ec --- /dev/null +++ b/src/AnalysisTools.jl @@ -0,0 +1,85 @@ +""" + $SIGNATURES + +Prunes factor graph to keep up to `upto` number of variables. + +Warning: uses functions that are outside of IncrementalInference (e.g., +`isSolvable()`), so will probably need to place this elsewhere. +""" +function shrinkFactorGraph(fg; upto::Int=6) + fgs = deepcopy(fg) + + delVars = filter(x->isSolvable(getVariable(fgs, x))==0, ls(fgs)) + todel = setdiff(lsf(fgs, solvable=0), lsf(fgs, solvable=1)) + delFcts = intersect(lsf(fgs), todel) + allMags = filter(x->:MAGNETOMETER in getTags(getFactor(fgs, x)), lsfPriors(fgs) ) + union!(delFcts, filter(x->length(ls(fgs, x))==0, allMags) ) + + union!(delVars, (ls(fgs, r"x\d") |> sortDFG)[upto:end]) + union!(delFcts, map(x->ls(fgs, x), delVars)...) + + map(x->deleteFactor!(fgs, x), delFcts) + map(x->deleteVariable!(fgs, x), delVars) + + fgs +end + + +""" + $SIGNATURES + +Deterministically get all trees associated with all possible variable orderings +of `dfg` factor graph. Returns a dictionary with (tree, ordering) tuples. + +Warning: factorial number of possibilities, so use carefully! +""" +function getAllTrees(fg::AbstractDFG) + dfg = loadCanonicalFG_Kaess() + variables = ls(dfg) + orderings = permutations(variables) |> collect + + # Dimensionality check to make sure we do not break your computer. + max_dimension = 11 # something reasonable (11! ~ 40M). + if length(variables) > 11 + throw(ArgumentError("You crazy! dfg is too big. Factorial explosion.")) + end + + # Produce a tree for each ordering, and store in dictionary. + all_trees = Dict{Int, Tuple{BayesTree, Vector{Symbol}}}() + for i in 1:length(orderings) + all_trees[i] = (resetBuildTreeFromOrder!(fg, orderings[i]), orderings[i]) + end + + return all_trees +end + + +""" + $SIGNATURES + +Get number of non-zero entries for clique's frontal components. Num of non-zero +matrix entries is just the fully dense upper triangular part of square matrix. +""" +function nnzFrontals(dimension) + if dimension == 1 + return 1 + else + # Solved recurrence for n + (n-1) + ... + 2 + 1. + return (dimension * (dimension + 1)) / 2 + end +end + + + +""" + $SIGNATURES + +Get total number of non-zero entries for a clique. Num of non-zero matrix +entries is the fully dense upper triangular part (frontals) plus the +(frontal x separator)-size rectangle. +""" +function nnzClique(clique) + frontal_dim = length(getCliqFrontalVarIds(clique)) + separator_dim = length(getCliqSeparatorVarIds(clique)) + return nnzFrontals(frontal_dim) + (frontal_dim * separator_dim) +end diff --git a/test/testAnalysisTools.jl b/test/testAnalysisTools.jl new file mode 100644 index 000000000..f55dbc10d --- /dev/null +++ b/test/testAnalysisTools.jl @@ -0,0 +1,23 @@ +# Test for tree-based analysis tools found in `AnalysisTools.jl`. +using Test +using IncrementalInference +using RoME # Used for loading canonical graphs (is this ok?). + +@testset "Number of non-zero calculation for frontals." begin + # Alternative way of calculating number of upper triangular matrix elements. + nnzFrontalsRecursive(dim) = dim==1 ? 1 : dim + nnzFrontalsRecursive(dim-1) + # Both must agree for any integer number dimension. + for dim in 1:100 + @test nnzFrontalsRecursive(dim) == nnzFrontals(dim) + end +end + +@testset "Number of non-zero calculation for full cliques." begin + fg = loadCanonicalFG_Kaess() + vo = [:l1, :l2, :x1, :x2, :x3] + tree = buildTreeFromOrdering!(fg, vo) + # Must agree with hand-calculated values, iSAM2 paper. + @test nnzClique(tree.cliques[1]) == 3 + @test nnzClique(tree.cliques[2]) == 5 + @test nnzClique(tree.cliques[3]) == 2 +end From 0153e289f93357ccf513db699dc6b45bdf5cf94c Mon Sep 17 00:00:00 2001 From: antonio teran Date: Fri, 20 Dec 2019 10:01:28 -0800 Subject: [PATCH 02/57] Add num of non zeros fxn for trees. --- src/AnalysisTools.jl | 15 +++++++++++++++ test/testAnalysisTools.jl | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl index aea7643ec..b4b21ef58 100644 --- a/src/AnalysisTools.jl +++ b/src/AnalysisTools.jl @@ -83,3 +83,18 @@ function nnzClique(clique) separator_dim = length(getCliqSeparatorVarIds(clique)) return nnzFrontals(frontal_dim) + (frontal_dim * separator_dim) end + + +""" + $SIGNATURES + +Get total number of non-zero entries for a Bayes tree. Num of non-zero matrix +entries is the sum of all non-zero entries for each individual clique. +""" +function nnzTree(tree::BayesTree) + nnzTot = 0 + for (cliqid, cliq) in tree.cliques + nnzTot += nnzClique(cliq) + end + return nnzTot +end diff --git a/test/testAnalysisTools.jl b/test/testAnalysisTools.jl index f55dbc10d..d8b152c1f 100644 --- a/test/testAnalysisTools.jl +++ b/test/testAnalysisTools.jl @@ -21,3 +21,11 @@ end @test nnzClique(tree.cliques[2]) == 5 @test nnzClique(tree.cliques[3]) == 2 end + +@testset "Number of non-zero calculation for full trees." begin + fg = loadCanonicalFG_Kaess() + vo = [:l1, :l2, :x1, :x2, :x3] + tree = buildTreeFromOrdering!(fg, vo) + # Must agree with hand-calculated values, iSAM2 paper. + @test nnzTree(tree) == 10 +end From b51a5f9d304a6525f42d9fce59bd73f3ec959a6b Mon Sep 17 00:00:00 2001 From: antonio teran Date: Fri, 20 Dec 2019 18:57:08 -0800 Subject: [PATCH 03/57] Add cost functions for trees and an sample analysis file. --- examples/TreeAnalysis.jl | 53 +++++++++++++++++++++++++++++++++ src/AnalysisTools.jl | 64 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 examples/TreeAnalysis.jl diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl new file mode 100644 index 000000000..b66c85bb1 --- /dev/null +++ b/examples/TreeAnalysis.jl @@ -0,0 +1,53 @@ +# Showcasing the available analysis tools for the Bayes (Junction) tree. +using IncrementalInference +using DistributedFactorGraphs # For `isSolvable` function. +using RoME # For loading canonical graphs (e.g., Kaess' example). +using Combinatorics # For creating the variable ordering `permutations`. +using Gadfly + +latex_fonts = Theme(major_label_font="CMU Serif", major_label_font_size=16pt, + minor_label_font="CMU Serif", minor_label_font_size=14pt, + key_title_font="CMU Serif", key_title_font_size=12pt, + key_label_font="CMU Serif", key_label_font_size=10pt) +Gadfly.push_theme(latex_fonts) + +# Get tree for each variable ordering in a factor graph. +fg = loadCanonicalFG_Kaess() +all_trees = getAllTrees(fg) + +# scores stores: (tree key ID, nnz, cost fxn 1, cost fxn 2). +unsorted_scores = Vector{Tuple{Int, Float64, Float64, Float64}}() +for key in keys(all_trees) + e = all_trees[key] # (Bayes tree, var order, nnz) + tree = e[1] # Get the Bayes tree. + cost1 = getTreeCost_01(tree) + cost2 = getTreeCost_02(tree) + push!(unsorted_scores, (key, e[3], cost1, cost2)) +end + +# Sort them to make sure the keys are in order. +scores = sort(unsorted_scores) + +# Separate scores into vectors for plotting. +all_nnzs = (x->(x[2])).(scores) +costs_01 = (x->(x[3])).(scores) +costs_02 = (x->(x[4])).(scores) + +bincnt = 20 +Gadfly.plot(x=all_nnzs, y=costs_02, + Geom.hexbin(xbincount=bincnt, ybincount=bincnt), + Guide.xlabel("Number of non zeros [int]"), + Guide.ylabel("Tree cost [cfxn2]")) + +min_ids_02 = findall(x->x == minimum(costs_02), costs_02) +max_ids_02 = findall(x->x == maximum(costs_02), costs_02) + +min_ids_nnz = findall(x->x == minimum(all_nnzs), all_nnzs) +max_ids_nnz = findall(x->x == maximum(all_nnzs), all_nnzs) + +# Find the intersection between best on both rubrics (lower left quadrant). +best_ids = findall(x->x in min_ids_02, min_ids_nnz) +# Find good factorizations but bad trees (upper left quadrant). +bad_trees_good_mats_ids = findall(x->x in max_ids_02, min_ids_nnz) +# Find good trees with bad matrix factorizations (lower right quadrant). +good_trees_bad_mats_ids = min_ids_02[findall(x->x == maximum(all_nnzs[min_ids_02]), all_nnzs[min_ids_02])] diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl index b4b21ef58..d6c80dac1 100644 --- a/src/AnalysisTools.jl +++ b/src/AnalysisTools.jl @@ -29,7 +29,7 @@ end $SIGNATURES Deterministically get all trees associated with all possible variable orderings -of `dfg` factor graph. Returns a dictionary with (tree, ordering) tuples. +of `dfg` factor graph. Returns a dictionary with (tree, ordering, nnz) tuples. Warning: factorial number of possibilities, so use carefully! """ @@ -45,9 +45,11 @@ function getAllTrees(fg::AbstractDFG) end # Produce a tree for each ordering, and store in dictionary. - all_trees = Dict{Int, Tuple{BayesTree, Vector{Symbol}}}() + all_trees = Dict{Int, Tuple{BayesTree, Vector{Symbol}, Float64}}() for i in 1:length(orderings) - all_trees[i] = (resetBuildTreeFromOrder!(fg, orderings[i]), orderings[i]) + tree = resetBuildTreeFromOrder!(fg, orderings[i]) + nnz = nnzTree(tree) + all_trees[i] = (tree, orderings[i], nnz) end return all_trees @@ -98,3 +100,59 @@ function nnzTree(tree::BayesTree) end return nnzTot end + + +""" + $SIGNATURES + +Get total number of non-zero entries for a factor graph's upper triangular +square root information matrix, i.e., R matrix in A = Q[R 0]^T, using the QR's +factorization algorithm variable ordering. +""" +function nnzSqrtInfoMatrix(A::Matrix) + q,r,p = qr(A, Val(true)) + r .= abs.(r) + nz = 1e-5 .< r + r[nz] .= 1 + sum(nz) +end + + +""" + $SIGNATURES + +Simple cost function for ranking the structure of a Bayes tree. Weighting: + cost = (max tree depth) * (max clique dimension)^alpha +""" +function getTreeCost_01(tree::BayesTree; alpha::Float64=1.0 ) + cliqs = tree.cliques |> values |> collect + maxdepth = map(x->getCliqDepth(tree, x)+1, cliqs) |> maximum + maxdim = length.(map(x->getCliqVarIdsAll(x), cliqs)) |> maximum + + return maxdepth * (maxdim^alpha) +end + + +""" + $SIGNATURES + +Cost function for ranking the structure of a Bayes tree, putting and emphasis on +wider but shallower trees by penalizing the average number of siblings. +Weighting: + cost = 1/(total num of child / num of parents) * + (max tree depth) * (max clique dimension)^alpha +""" +function getTreeCost_02(tree::BayesTree; alpha::Float64=1.0) + # Frontal and number of children. + ARR = Tuple{Symbol, Int}[] + for (cliqid, vex) in tree.cliques + afrtl = getCliqFrontalVarIds(tree.cliques[cliqid])[1] + numch = length(getChildren(tree, afrtl)) + push!(ARR, (afrtl, numch)) + end + + numParents = filter(x->0 length + totalNumChildren = (x->x[2]).(ARR) |> sum + + return getTreeCost_01(tree, alpha=alpha)/(totalNumChildren/numParents) +end From cf36353b5e1dbef1989a740ed0d386f0798bbe4a Mon Sep 17 00:00:00 2001 From: antonio teran Date: Sat, 21 Dec 2019 00:00:24 -0800 Subject: [PATCH 04/57] Add amd, colamd, and ccolamd orderings. --- examples/TreeAnalysis.jl | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl index b66c85bb1..13bc4106c 100644 --- a/examples/TreeAnalysis.jl +++ b/examples/TreeAnalysis.jl @@ -3,7 +3,8 @@ using IncrementalInference using DistributedFactorGraphs # For `isSolvable` function. using RoME # For loading canonical graphs (e.g., Kaess' example). using Combinatorics # For creating the variable ordering `permutations`. -using Gadfly +using SuiteSparse.CHOLMOD: SuiteSparse_long # For CCOLAMD constraints. +using Gadfly # For histogram and scatter plots. latex_fonts = Theme(major_label_font="CMU Serif", major_label_font_size=16pt, minor_label_font="CMU Serif", minor_label_font_size=14pt, @@ -13,7 +14,7 @@ Gadfly.push_theme(latex_fonts) # Get tree for each variable ordering in a factor graph. fg = loadCanonicalFG_Kaess() -all_trees = getAllTrees(fg) +all_trees = getAllTrees(deepcopy(fg)) # scores stores: (tree key ID, nnz, cost fxn 1, cost fxn 2). unsorted_scores = Vector{Tuple{Int, Float64, Float64, Float64}}() @@ -51,3 +52,27 @@ best_ids = findall(x->x in min_ids_02, min_ids_nnz) bad_trees_good_mats_ids = findall(x->x in max_ids_02, min_ids_nnz) # Find good trees with bad matrix factorizations (lower right quadrant). good_trees_bad_mats_ids = min_ids_02[findall(x->x == maximum(all_nnzs[min_ids_02]), all_nnzs[min_ids_02])] + +# Get AMDs variable ordering. +amd_ordering = getEliminationOrder(fg) +amd_tree = buildTreeFromOrdering!(deepcopy(fg), amd_ordering) +amd_tree_nnz = nnzTree(amd_tree) +amd_tree_cost02 = getTreeCost_02(amd_tree) + +# Get CCOLAMD variable ordering. First bring in CCOLAMD. +include(normpath(Base.find_package("IncrementalInference"), "..", "ccolamd.jl")) +A, varsym, fctsym = getAdjacencyMatrixSparse(fg) +colamd_ordering = varsym[Ccolamd.ccolamd(A)] +colamd_tree = buildTreeFromOrdering!(deepcopy(fg), colamd_ordering) +colamd_tree_nnz = nnzTree(colamd_tree) +colamd_tree_cost02 = getTreeCost_02(colamd_tree) + +# Now add the iSAM2 constraint. +cons = zeros(SuiteSparse_long, length(A.colptr) - 1) +cons[findall(x->x == :x3, varsym)[1]] = 1 # NOTE(tonioteran) hardcoded for Kaess' example. +ccolamd_ordering = varsym[Ccolamd.ccolamd(A, cons)] +ccolamd_tree = buildTreeFromOrdering!(deepcopy(fg), ccolamd_ordering) +ccolamd_tree_nnz = nnzTree(ccolamd_tree) +ccolamd_tree_cost02 = getTreeCost_02(ccolamd_tree) + +# Plot both data points. From 4b0f7433b4011eb7dca1dbd17c2bb65a9261bd4c Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 27 Dec 2019 18:18:25 -0500 Subject: [PATCH 05/57] dispatch build subgraph --- src/CliqStateMachineUtils.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index fe254a107..ec6edee14 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -144,7 +144,7 @@ function sandboxCliqResolveStep(tree::BayesTree, hist = getCliqSolveHistory(tree, frontal) # clear Condition states to allow step solve getData(hist[step][4].cliq).solveCondition = Condition() - + # cond = getSolveCondition(hist[step][4].cliq) # cond = Any[] return sandboxStateMachineStep(hist, step) @@ -1011,7 +1011,7 @@ DevNotes function buildCliqSubgraph(dfg::AbstractDFG, treel::BayesTree, cliq::Graphs.ExVertex, - subfg::InMemDFGType=GraphsDFG(params=getSolverParams(dfg)) ) + subfg::InMemoryDFGTypes=GraphsDFG(params=getSolverParams(dfg)) ) # # get cliq and variable labels syms = getCliqAllVarIds(cliq) From e7a0dfb1e0de2f17d5c5214cd76150f36ba10423 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 29 Dec 2019 20:09:08 -0500 Subject: [PATCH 06/57] tabulate Travis badges --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 962f3c652..d812fc226 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # IncrementalInference.jl -[![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=master)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) -[![codecov.io](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl?branch=master) +Stable | Dev | Coverage +-------|-----|--------- +[![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=master)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=release/v0.8)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![codecov.io](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl?branch=master) Optimization routines for incremental non-parametric and parametric solutions based on factor graphs and the Bayes (Junction) tree implemented in the [Julia language](http://www.julialang.org/) (and [JuliaPro](http://www.juliacomputing.com)). From 601d838e4918b78615ce935687bd68300ddb9315 Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 1 Jan 2020 23:50:54 -0500 Subject: [PATCH 07/57] Update README.md --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d812fc226..423d0408f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # IncrementalInference.jl -Stable | Dev | Coverage --------|-----|--------- -[![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=master)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=release/v0.8)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![codecov.io](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl?branch=master) +> Click on badges to follow links + +Stable | Dev | Coverage | Documentation +-------|-----|----------|-------------- +[![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=master)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![Build Status](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl.svg?branch=release/v0.8)](https://travis-ci.org/JuliaRobotics/IncrementalInference.jl) | [![codecov.io](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl/coverage.svg?branch=master)](https://codecov.io/github/JuliaRobotics/IncrementalInference.jl?branch=master) | [![docs](https://img.shields.io/badge/docs-latest-blue.svg)](http://juliarobotics.github.io/Caesar.jl/latest/) Optimization routines for incremental non-parametric and parametric solutions based on factor graphs and the Bayes (Junction) tree implemented in the [Julia language](http://www.julialang.org/) (and [JuliaPro](http://www.juliacomputing.com)). @@ -12,10 +14,6 @@ Optimization routines for incremental non-parametric and parametric solutions ba This package furthermore forms a cardinal piece of the [Caesar.jl](https://github.com/JuliaRobotics/Caesar.jl) robotics toolkit, including 3D visualization and database interaction, which can serve as a base station for a robotic platform. A standalone [Robot Motion Estimate](https://github.com/JuliaRobotics/RoME.jl) package is also available. -# Documentation - -Please see the [common Caesar.jl documentation](http://juliarobotics.github.io/Caesar.jl/latest/): -[![docs](https://img.shields.io/badge/docs-latest-blue.svg)](http://juliarobotics.github.io/Caesar.jl/latest/) Introduction ------------ From 26fad9e90e34dcad779fb5c477db216f333de466 Mon Sep 17 00:00:00 2001 From: dehann Date: Sat, 4 Jan 2020 16:40:39 -0500 Subject: [PATCH 08/57] ex2 test from #458 --- src/SolverUtilities.jl | 2 +- test/testCliqueFactors.jl | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/SolverUtilities.jl b/src/SolverUtilities.jl index 758a7072b..7a5fb8860 100644 --- a/src/SolverUtilities.jl +++ b/src/SolverUtilities.jl @@ -282,7 +282,7 @@ function solveFactorMeasurements(dfg::AbstractDFG, varsyms = fcto._variableOrderSymbols vars = map(x->getPoints(getKDE(dfg,x)), varsyms) fcttype = getFactorType(fcto) - zDim = getData(fcto).fnc.zDim + zDim = solverData(fcto).fnc.zDim N = size(vars[1])[2] res = zeros(zDim) diff --git a/test/testCliqueFactors.jl b/test/testCliqueFactors.jl index a9f1cc89c..1d30ec559 100644 --- a/test/testCliqueFactors.jl +++ b/test/testCliqueFactors.jl @@ -95,10 +95,33 @@ end -@testset "Test clique factors, #458 Example 1" begin +@testset "Test clique factors, #458 Example 2" begin @warn "Test for Example 2 from 458 must still be coded." +fg = initfg() + +addVariable!(fg, :x0, ContinuousScalar) +addVariable!(fg, :x1, ContinuousScalar) +addVariable!(fg, :x2, ContinuousScalar) +addVariable!(fg, :x3, ContinuousScalar) + +addVariable!(fg, :lm0, ContinuousScalar) +addVariable!(fg, :lm3, ContinuousScalar) + +lc = LinearConditional(Normal()) +lp = Prior(Normal()) +addFactor!(fg, [:x0;:x1], lc, autoinit=false) +addFactor!(fg, [:x1;:x2], lc, autoinit=false) +addFactor!(fg, [:x2;:x3], lc, autoinit=false) +addFactor!(fg, [:x3;:x4], lc, autoinit=false) + +addFactor!(fg, [:x0;:lm0], lc, autoinit=false) +addFactor!(fg, [:x1;:lm0], lc, autoinit=false) +addFactor!(fg, [:x2;:lm3], lc, autoinit=false) +addFactor!(fg, [:x3;:lm3], lc, autoinit=false) + + end From ce57b80c7a155f85046eed14dda23ba08d2c2f75 Mon Sep 17 00:00:00 2001 From: dehann Date: Sat, 4 Jan 2020 23:44:21 -0500 Subject: [PATCH 09/57] wip --- test/testCliqueFactors.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/testCliqueFactors.jl b/test/testCliqueFactors.jl index 1d30ec559..23ea29e66 100644 --- a/test/testCliqueFactors.jl +++ b/test/testCliqueFactors.jl @@ -114,13 +114,26 @@ lp = Prior(Normal()) addFactor!(fg, [:x0;:x1], lc, autoinit=false) addFactor!(fg, [:x1;:x2], lc, autoinit=false) addFactor!(fg, [:x2;:x3], lc, autoinit=false) -addFactor!(fg, [:x3;:x4], lc, autoinit=false) addFactor!(fg, [:x0;:lm0], lc, autoinit=false) addFactor!(fg, [:x1;:lm0], lc, autoinit=false) addFactor!(fg, [:x2;:lm3], lc, autoinit=false) addFactor!(fg, [:x3;:lm3], lc, autoinit=false) +# particular order from 458 +vo = Symbol[:x0, :x2, :x1, :lm3, :lm0, :x3] + +tree = resetBuildTreeFromOrder!(fg, vo) +drawTree(tree, show=true) +# getSolverParams(fg).dbg = true +# tree, smt, hist = solveTree!(fg, variableOrder=vo) + +sfg = buildCliqSubgraph(fg,tree,:x3) +# drawGraph(sfg, show=true) + +## WIP +# getCliqFactorIdsAll(tree, :x3) + end From cb581c9272cd99f1035725ed0717b338330e318b Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 5 Jan 2020 13:56:41 -0500 Subject: [PATCH 10/57] test for factors in cliques --- test/testCliqueFactors.jl | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/test/testCliqueFactors.jl b/test/testCliqueFactors.jl index 23ea29e66..147230bfe 100644 --- a/test/testCliqueFactors.jl +++ b/test/testCliqueFactors.jl @@ -120,23 +120,46 @@ addFactor!(fg, [:x1;:lm0], lc, autoinit=false) addFactor!(fg, [:x2;:lm3], lc, autoinit=false) addFactor!(fg, [:x3;:lm3], lc, autoinit=false) + # particular order from 458 vo = Symbol[:x0, :x2, :x1, :lm3, :lm0, :x3] - tree = resetBuildTreeFromOrder!(fg, vo) -drawTree(tree, show=true) -# getSolverParams(fg).dbg = true -# tree, smt, hist = solveTree!(fg, variableOrder=vo) +# drawTree(tree, show=true) -sfg = buildCliqSubgraph(fg,tree,:x3) -# drawGraph(sfg, show=true) +sfg_1 = buildCliqSubgraph(fg,tree,:x3) +sfg_2 = buildCliqSubgraph(fg,tree,:x2) +sfg_3 = buildCliqSubgraph(fg,tree,:x0) +# drawGraph(sfg_1, show=true) +# drawGraph(sfg_2, show=true) +# drawGraph(sfg_3, show=true) ## WIP -# getCliqFactorIdsAll(tree, :x3) +C1_fcts = [:x1lm0f1; :x3lm3f1] +C2_fcts = [:x1x2f1; :x2x3f1; :x2lm3f1] +C3_fcts = [:x0x1f1; :x0lm0f1] + +# check all factors are accounted for +@test union(C1_fcts, C2_fcts, C3_fcts) |> length == lsf(fg) |> length +@test intersect(C1_fcts, C2_fcts) |> length == 0 +@test intersect(C1_fcts, C3_fcts) |> length == 0 +@test intersect(C2_fcts, C3_fcts) |> length == 0 + +# clique 1 +@test intersect(getCliqFactorIdsAll(tree, :x3), C1_fcts) |> length == 2 +@test intersect(lsf(sfg_1), C1_fcts) |> length == 2 + +# clique 2 +@test intersect( getCliqFactorIdsAll(tree, :x2), C2_fcts) |> length == 3 +@test intersect( lsf(sfg_2), C2_fcts) |> length == 3 + +# clique 3 +@test intersect( getCliqFactorIdsAll(tree, :x0), C3_fcts) |> length == 2 +@test intersect( lsf(sfg_3), C3_fcts) |> length == 2 end + # From 908da7c4ad2ad2f0587d4323b7cdbee840d93964 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 5 Jan 2020 14:00:40 -0500 Subject: [PATCH 11/57] also check old factors for ex1 --- test/testCliqueFactors.jl | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/testCliqueFactors.jl b/test/testCliqueFactors.jl index 147230bfe..9f6083b70 100644 --- a/test/testCliqueFactors.jl +++ b/test/testCliqueFactors.jl @@ -35,11 +35,8 @@ addFactor!(fg, [:x2;:l1], lc, autoinit=false) addFactor!(fg, [:x0;], lp, autoinit=false) addFactor!(fg, [:l0;], lp, autoinit=false) +# build tree vo = Symbol[:x2, :x0, :l0, :x3, :x1, :l1, :x4] -# getSolverParams(fg).dbg = true -# tree, smt, hist = solveTree!(fg, variableOrder=vo) - - tree = resetBuildTreeFromOrder!(fg, vo) # drawTree(tree, show=true) @@ -59,31 +56,38 @@ lsvars = ls(fg) ## Now check if factors in cliques are okay -C3_fg = buildCliqSubgraph(fg, tree, getCliq(tree, :x0) ) +C3 = getCliq(tree, :x0) +C3_fg = buildCliqSubgraph(fg, tree, C3 ) # drawGraph(C3_fg, show=true) C3_fcts = [:x0l0f1;:x0l1f1;:x0x1f1;:x0f1] @test intersect(ls(C3_fg), [:x0; :x1; :l0; :l1]) |> length == 4 @test intersect(lsf(C3_fg), C3_fcts) |> length == length(C3_fcts) +@test intersect(getCliqFactorIdsAll(C3), C3_fcts) |> length == length(C3_fcts) -C2_fg = buildCliqSubgraph(fg, tree, getCliq(tree, :l0) ) +C2 = getCliq(tree, :l0) +C2_fg = buildCliqSubgraph(fg, tree, C2) # drawGraph(C2_fg, show=true) C2_fcts = [:x1x2f1; :x2x3f1; :x2l0f1; :x2l1f1; :l0f1] @test intersect(ls(C2_fg), [:x3; :x2; :x1; :l0; :l1]) |> length == 5 @test intersect(lsf(C2_fg), C2_fcts) |> length == length(C2_fcts) +@test intersect(getCliqFactorIdsAll(C2), C2_fcts) |> length == length(C2_fcts) -C1_fg = buildCliqSubgraph(fg, tree, getCliq(tree, :x4) ) +C1 = getCliq(tree, :x4) +C1_fg = buildCliqSubgraph(fg, tree, C1) # drawGraph(C1_fg, show=true) C1_fcts = [:x3x4f1;] @test intersect(ls(C1_fg), [:x3; :x4; :x1; :l1]) |> length == 4 @test intersect(lsf(C1_fg), C1_fcts) |> length == length(C1_fcts) +@test intersect(getCliqFactorIdsAll(C1), C1_fcts) |> length == length(C1_fcts) + # check that all factors are counted allCliqFcts = union(C1_fcts, C2_fcts, C3_fcts) From d81cb06dcec1110a86cee95f4e13a0b9a1e96578 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 5 Jan 2020 16:01:06 -0500 Subject: [PATCH 12/57] test for orphaned FGs --- test/runtests.jl | 2 ++ test/testSolveOrphanedFG.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 test/testSolveOrphanedFG.jl diff --git a/test/runtests.jl b/test/runtests.jl index ac1c6c8a1..a8942ba95 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -58,6 +58,8 @@ include("testBasicGraphs.jl") include("testlocalconstraintexamples.jl") end +# include("testSolveOrphanedFG.jl") + # include("priorusetest.jl") include("testExplicitMultihypo.jl") diff --git a/test/testSolveOrphanedFG.jl b/test/testSolveOrphanedFG.jl new file mode 100644 index 000000000..3079897f1 --- /dev/null +++ b/test/testSolveOrphanedFG.jl @@ -0,0 +1,28 @@ +# test forest of graphs can solve with CSM, + +using IncrementalInference +using Test + + + +@testset "Test forest of orphaned graphs" + +fg = initfg() +addVariable!(fg, :x0, ContinuousScalar) +addFactor!(fg, [:x0;], Prior(Normal())) +addVariable!(fg, :x1, ContinuousScalar) +addFactor!(fg, [:x0;:x1], LinearConditional(Normal())) + +fg = initfg() +addVariable!(fg, :x10, ContinuousScalar) +addFactor!(fg, [:x10;], Prior(Normal())) +addVariable!(fg, :x11, ContinuousScalar) +addFactor!(fg, [:x10;:x11], LinearConditional(Normal())) + +# solve factor graph with two orphaned components +tree, smt, hist = solveTree!(fg) + +# test tree will have two different root nodes +# ... + +end From ec0d6f2cd463ef9f16f9fcd8bfa3a1284039df67 Mon Sep 17 00:00:00 2001 From: dehann Date: Mon, 6 Jan 2020 03:05:42 -0500 Subject: [PATCH 13/57] add tree build time --- src/JunctionTree.jl | 2 ++ src/JunctionTreeTypes.jl | 4 +++- src/SolverAPI.jl | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 590f5bd57..6d740bc3b 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -372,6 +372,7 @@ function buildTreeFromOrdering!(dfg::G, maxparallel::Int=50, solvable::Int=1 ) where G <: InMemoryDFGTypes # + t0 =time_ns() println() fge = deepcopy(dfg) @info "Building Bayes net..." @@ -394,6 +395,7 @@ function buildTreeFromOrdering!(dfg::G, cliq = tree.cliques[1] # start at the root buildCliquePotentials(dfg, tree, cliq, solvable=solvable); # fg does not have the marginals as fge does + tree.buildTime = (time_ns()-t0)/1e9 return tree end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index c42f086b8..b08cdd377 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -15,6 +15,7 @@ mutable struct BayesTree cliques::Dict{Int,Graphs.ExVertex} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} + buildTime::Float64 end function emptyBayesTree() @@ -23,7 +24,8 @@ function emptyBayesTree() Dict{Int,Graphs.ExVertex}(), #[], Dict{AbstractString, Int}(), - Symbol[] ) + Symbol[], + 0.0 ) return bt end diff --git a/src/SolverAPI.jl b/src/SolverAPI.jl index ce861a9be..012509169 100644 --- a/src/SolverAPI.jl +++ b/src/SolverAPI.jl @@ -55,6 +55,8 @@ function solveTree!(dfgl::G, oldtree.btid = tree.btid oldtree.cliques = tree.cliques oldtree.frontals = tree.frontals + oldtree.variableOrder = tree.variableOrder + oldtree.buildTime = tree.buildTime return oldtree, smtasks, hist end From 341133e4674a92bfef3bb8602f32c176c5d6106c Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 7 Jan 2020 10:59:52 +0200 Subject: [PATCH 14/57] fixes #523 GraphsDFG -> InMemDFGTyp --- src/CliqStateMachineUtils.jl | 4 ++-- src/JunctionTreeTypes.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index ec6edee14..66a6898ec 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -1011,7 +1011,7 @@ DevNotes function buildCliqSubgraph(dfg::AbstractDFG, treel::BayesTree, cliq::Graphs.ExVertex, - subfg::InMemoryDFGTypes=GraphsDFG(params=getSolverParams(dfg)) ) + subfg::InMemoryDFGTypes=InMemDFGType(params=getSolverParams(dfg)) ) # # get cliq and variable labels syms = getCliqAllVarIds(cliq) @@ -1041,7 +1041,7 @@ end function buildCliqSubgraph(fgl::AbstractDFG, treel::BayesTree, cliqsym::Symbol, - subfg::InMemDFGType=GraphsDFG(params=getSolverParams(fgl)) ) + subfg::InMemDFGType=InMemDFGType(params=getSolverParams(fgl)) ) # buildCliqSubgraph(fgl, treel, getCliq(treel, cliqsym), subfg) end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index c42f086b8..dd6b9b4b0 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -53,7 +53,7 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem refactoring::Dict{Symbol, String} oldcliqdata::BTND logger::SimpleLogger - CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, DFG.GraphsDFG, DFG.GraphsDFG}() # NOTE JT - GraphsDFG as default? + CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() # NOTE JT - GraphsDFG as default? CliqStateMachineContainer{BTND}(x1::G, x2::InMemoryDFGTypes, x3::BayesTree, From 8febbd2f3da8a500b89d6472b3484eb9f1283b4f Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 7 Jan 2020 12:27:33 +0200 Subject: [PATCH 15/57] find and replace TreeClique -> Graphs.ExVertex --- .gitignore | 2 + src/AdditionalUtils.jl | 2 +- src/CliqStateMachine.jl | 4 +- src/CliqStateMachineUtils.jl | 26 ++++---- src/Deprecated.jl | 64 +++++++++--------- src/DispatchPackedConversions.jl | 2 +- src/FactorGraph01.jl | 18 ++--- src/FactorGraphTypes.jl | 16 ++--- src/IncrementalInference.jl | 4 +- src/InferDimensionUtils.jl | 12 ++-- src/JunctionTree.jl | 96 +++++++++++++-------------- src/JunctionTreeTypes.jl | 30 ++++----- src/SolveTree01.jl | 34 +++++----- src/SolverUtilities.jl | 2 +- src/TreeBasedInitialization.jl | 76 ++++++++++----------- test/unittests/FactorGraph01_tests.jl | 2 +- 16 files changed, 197 insertions(+), 193 deletions(-) diff --git a/.gitignore b/.gitignore index 0ed720739..96de1928a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ test/tmp/*.dot test/tmp/*.tex Manifest.toml + +dev diff --git a/src/AdditionalUtils.jl b/src/AdditionalUtils.jl index 4afcaed76..02d4cb0ce 100644 --- a/src/AdditionalUtils.jl +++ b/src/AdditionalUtils.jl @@ -77,7 +77,7 @@ Related printCliqHistorySummary """ function printCliqSummary(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger() ) where G <: AbstractDFG # frtl = getCliqFrontalVarIds(cliq) diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 9aaab477c..19276ae81 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -846,7 +846,7 @@ Notes: """ function cliqInitSolveUpByStateMachine!(dfg::G, tree::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; N::Int=100, oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), drawtree::Bool=false, @@ -859,7 +859,7 @@ function cliqInitSolveUpByStateMachine!(dfg::G, delay::Bool=false, logger::SimpleLogger=SimpleLogger(Base.stdout)) where {G <: AbstractDFG, AL <: AbstractLogger} # - children = Graphs.ExVertex[] + children = TreeClique[] for ch in Graphs.out_neighbors(cliq, tree.bt) push!(children, ch) end diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index ec6edee14..bae7ba8e1 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -53,7 +53,7 @@ Return clique state machine history from `tree` if it was solved with `recordcli Notes - Cliques are identified by front variable `::Symbol` which are always unique across the cliques. """ -function getCliqSolveHistory(cliq::Graphs.ExVertex) +function getCliqSolveHistory(cliq::TreeClique) getData(cliq).statehistory end function getCliqSolveHistory(tree::BayesTree, frntal::Symbol) @@ -119,7 +119,7 @@ function printCliqHistorySummary(hists::Dict{Int,Vector{Tuple{DateTime, Int, Fun end -function printCliqHistorySummary(cliq::Graphs.ExVertex) +function printCliqHistorySummary(cliq::TreeClique) hist = getCliqSolveHistory(cliq) printCliqHistorySummary(hist) end @@ -260,7 +260,7 @@ function solveCliqWithStateMachine!(dfg::G, prevcsmc::Union{Nothing,CliqStateMachineContainer}=nothing) where G <: AbstractDFG # cliq = whichCliq(tree, frontal) - children = Graphs.ExVertex[] + children = TreeClique[] for ch in Graphs.out_neighbors(cliq, tree.bt) push!(children, ch) end @@ -397,7 +397,7 @@ Dev Notes - Very closely related to getCliqSiblingsPartialNeeds -- refactor likely (NOTE). - should precompute `allinters`. """ -function getSiblingsDelayOrder(tree::BayesTree, cliq::Graphs.ExVertex, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getSiblingsDelayOrder(tree::BayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # when is a cliq upsolved solvedstats = Symbol[:upsolved; :marginalized; :uprecycled] @@ -546,7 +546,7 @@ Determine clique truely isn't able to proceed any further: - change status to :mustinitdown if have only partial beliefs so far: - combination of status, while partials belief siblings are not :mustinitdown """ -function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::Graphs.ExVertex, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # which incoming messages are partials hasPartials = Dict{Symbol, Int}() for (sym, tmsg) in dwinmsgs @@ -605,7 +605,7 @@ notifyCSMCondition(tree::BayesTree, frsym::Symbol) = notify(getSolveCondition(wh Store/cache a clique's solvable dimensions. """ -function updateCliqSolvableDims!(cliq::Graphs.ExVertex, +function updateCliqSolvableDims!(cliq::TreeClique, sdims::Dict{Symbol, Float64}, logger=ConsoleLogger() )::Nothing # @@ -628,7 +628,7 @@ end Retrieve a clique's cached solvable dimensions (since last update). """ -function fetchCliqSolvableDims(cliq::Graphs.ExVertex)::Dict{Symbol,Float64} +function fetchCliqSolvableDims(cliq::TreeClique)::Dict{Symbol,Float64} cliqd = getData(cliq) if isready(cliqd.solvableDims) return cliqd.solvableDims.data[1] @@ -648,7 +648,7 @@ Notes - Return false if one of the siblings is still busy """ function areSiblingsRemaingNeedDownOnly(tree::BayesTree, - cliq::Graphs.ExVertex )::Bool + cliq::TreeClique )::Bool # stillbusylist = [:null; :initialized;] prnt = getParent(tree, cliq) @@ -797,7 +797,7 @@ Dev Notes """ function addDownVariableFactors!(dfg::G1, subfg::G2, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger(); solvable::Int=1 ) where {G1 <: AbstractDFG, G2 <: InMemoryDFGTypes} # @@ -849,7 +849,7 @@ end Calculate new and then set the down messages for a clique in Bayes (Junction) tree. """ function getSetDownMessagesComplete!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, prntDwnMsgs::TempBeliefMsg, logger=ConsoleLogger() )::Nothing where G <: AbstractDFG # @@ -888,7 +888,7 @@ Related Functions from Upward Inference directPriorMsgIDs, directFrtlMsgIDs, directAssignmentIDs, mcmcIterationIDs """ -function determineCliqVariableDownSequence(subfg::AbstractDFG, cliq::Graphs.ExVertex; solvable::Int=1) +function determineCliqVariableDownSequence(subfg::AbstractDFG, cliq::TreeClique; solvable::Int=1) frtl = getCliqFrontalVarIds(cliq) adj = DFG.getAdjacencyMatrix(subfg, solvable=solvable) @@ -927,7 +927,7 @@ Dev Notes - cleanup and updates required, and @spawn jl 1.3 """ function solveCliqDownFrontalProducts!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, opts::SolverParams, logger=ConsoleLogger(); MCIters::Int=3 )::Nothing where G <: AbstractDFG @@ -1010,7 +1010,7 @@ DevNotes """ function buildCliqSubgraph(dfg::AbstractDFG, treel::BayesTree, - cliq::Graphs.ExVertex, + cliq::TreeClique, subfg::InMemoryDFGTypes=GraphsDFG(params=getSolverParams(dfg)) ) # # get cliq and variable labels diff --git a/src/Deprecated.jl b/src/Deprecated.jl index ceceed5ce..a5f76dd87 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -3,12 +3,12 @@ function getShortestPathNeighbors(fgl::FactorGraph; - from::Graphs.ExVertex=nothing, - to::Graphs.ExVertex=nothing, + from::TreeClique=nothing, + to::TreeClique=nothing, neighbors::Int=0 ) edgelist = shortest_path(fgl.g, ones(num_edges(fgl.g)), from, to) - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() edgedict = edgelist2edgedict(edgelist) expandVertexList!(fgl, edgedict, vertdict) # grow verts for i in 1:neighbors @@ -19,8 +19,8 @@ function getShortestPathNeighbors(fgl::FactorGraph; end function subgraphShortestPath(fgl::FactorGraph; - from::Graphs.ExVertex=nothing, - to::Graphs.ExVertex=nothing, + from::TreeClique=nothing, + to::TreeClique=nothing, neighbors::Int=0 ) # vertdict = getShortestPathNeighbors(fgl, from=from, to=to, neighbors=neighbors) @@ -29,10 +29,10 @@ end # explore all shortest paths combinations in verts, add neighbors and reference subgraph function subGraphFromVerts(fgl::FactorGraph, - verts::Dict{Int,Graphs.ExVertex}; + verts::Dict{Int,TreeClique}; neighbors::Int=0 ) # - allverts = Dict{Int,Graphs.ExVertex}() + allverts = Dict{Int,TreeClique}() allkeys = collect(keys(verts)) len = length(allkeys) # union all shortest path combinations in a vertdict @@ -107,7 +107,7 @@ function subgraphFromVerts(fgl::FactorGraph, verts::Array{Int,1}; neighbors::Int=0 ) - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() for vert in verts vertdict[vert] = fgl.g.vertices[vert] end @@ -125,7 +125,7 @@ function subGraphFromVerts(fgl::FactorGraph, verts::T; neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}}} # - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() for vert in verts id = -1 vsym = Symbol(vert) @@ -143,7 +143,7 @@ end function subgraphFromVerts(fgl::FactorGraph, verts::T; - neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}, Dict{Int,Graphs.ExVertex}}} + neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}, Dict{Int,TreeClique}}} # @warn "`subgraphFromVerts` deprecated, use `subGraphFromVerts` instead." subGraphFromVerts(fgl, verts, neighbors=neighbors) @@ -159,7 +159,7 @@ end # TODO -- convert to use add_vertex! instead, since edges type must be made also function addVerticesSubgraph(fgl::FactorGraph, fgseg::FactorGraph, - vertdict::Dict{Int,Graphs.ExVertex}) + vertdict::Dict{Int,TreeClique}) for vert in vertdict fgseg.g.vertices[vert[1]] = vert[2] @@ -202,8 +202,8 @@ end Return array of all variable vertices in a clique. """ -function getCliqVars(subfg::FactorGraph, cliq::Graphs.ExVertex) - verts = Graphs.ExVertex[] +function getCliqVars(subfg::FactorGraph, cliq::TreeClique) + verts = TreeClique[] for vid in getCliqVars(subfg, cliq) push!(verts, getVert(subfg, vid, api=localapi)) end @@ -263,7 +263,7 @@ end Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -function upMsg(cliq::Graphs.ExVertex) +function upMsg(cliq::TreeClique) @warn "deprecated upMsg, use getUpMsg instead" getData(cliq).upMsg end @@ -277,7 +277,7 @@ end Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -function dwnMsg(cliq::Graphs.ExVertex) +function dwnMsg(cliq::TreeClique) @warn "deprecated dwnMsg, use getDwnMsgs instead" getData(cliq).dwnMsg end @@ -359,10 +359,10 @@ function downGibbsCliqueDensity(inp::ExploreTreeType{T}, end function prepDwnPreOrderStack!(bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}) + parentStack::Array{TreeClique,1}) # dwn message passing function nodedata = nothing - tempStack = Array{Graphs.ExVertex,1}() + tempStack = Array{TreeClique,1}() push!(tempStack, parentStack[1]) while ( length(tempStack) != 0 || nodedata != nothing ) @@ -382,7 +382,7 @@ function prepDwnPreOrderStack!(bt::BayesTree, nothing end -function findVertsAssocCliq(fgl::FactorGraph, cliq::Graphs.ExVertex) +function findVertsAssocCliq(fgl::FactorGraph, cliq::TreeClique) cliqdata = getData(cliq) IDS = [cliqdata.frontalIDs; cliqdata.separatorIDs] #inp.cliq.attributes["frontalIDs"] @@ -392,7 +392,7 @@ function findVertsAssocCliq(fgl::FactorGraph, cliq::Graphs.ExVertex) nothing end -function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::Graphs.ExVertex, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG +function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::TreeClique, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG # info("starting pett") # TODO -- expand this to grab only partial subsection from the fg and bt data structures @@ -407,7 +407,7 @@ end function dispatchNewDwnProc!(fg::G, bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, + parentStack::Array{TreeClique,1}, stkcnt::Int, refdict::Dict{Int,Future}; N::Int=100, @@ -428,7 +428,7 @@ function dispatchNewDwnProc!(fg::G, drawpdf ? drawTree(bt) : nothing end - emptr = BayesTree(nothing, 0, Dict{Int,Graphs.ExVertex}(), Dict{String,Int}()); + emptr = BayesTree(nothing, 0, Dict{Int,TreeClique}(), Dict{String,Int}()); for child in out_neighbors(cliq, bt.bt) # nodedata.cliq, nodedata.bt.bt haskey(refdict, child.index) ? error("dispatchNewDwnProc! -- why you already have dwnremoteref?") : nothing @@ -448,7 +448,7 @@ Notes """ function processPreOrderStack!(fg::G, bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, + parentStack::Array{TreeClique,1}, refdict::Dict{Int,Future}; N::Int=100, dbg::Bool=false, @@ -478,7 +478,7 @@ function downMsgPassingIterative!(startett::ExploreTreeType{T}; drawpdf::Bool=false ) where {T} # # this is where we launch the downward iteration process from - parentStack = Array{Graphs.ExVertex,1}() + parentStack = Array{TreeClique,1}() refdict = Dict{Int,Future}() # start at the given clique in the tree -- shouldn't have to be the root. @@ -496,8 +496,8 @@ function downMsgPassingIterative!(startett::ExploreTreeType{T}; end function prepPostOrderUpPassStacks!(bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, - childStack::Array{Graphs.ExVertex,1} ) + parentStack::Array{TreeClique,1}, + childStack::Array{TreeClique,1} ) # upward message passing preparation while ( length(parentStack) != 0 ) #2.1 Pop a node from first stack and push it to second stack @@ -523,7 +523,7 @@ Asynchronously perform up message passing, based on previoulsy prepared `chldstk """ function asyncProcessPostStacks!(fgl::G, bt::BayesTree, - chldstk::Vector{Graphs.ExVertex}, + chldstk::Vector{TreeClique}, stkcnt::Int, refdict::Dict{Int,Future}; N::Int=100, @@ -560,7 +560,7 @@ function asyncProcessPostStacks!(fgl::G, end @info "====================== Clique $(cliq.attributes["label"]) =============================" - emptr = BayesTree(nothing, 0, Dict{Int,Graphs.ExVertex}(), Dict{String,Int}()); + emptr = BayesTree(nothing, 0, Dict{Int,TreeClique}(), Dict{String,Int}()); pett = partialExploreTreeType(fgl, emptr, cliq, nothing, childMsgs) # bt # parent cliq pointer is not needed here, fix Graphs.jl first if haskey(cliq.attributes, "remoteref") @@ -596,7 +596,7 @@ Notes """ function processPostOrderStacks!(fg::G, bt::BayesTree, - childStack::Array{Graphs.ExVertex,1}; + childStack::Array{TreeClique,1}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false ) where G <: AbstractDFG @@ -636,8 +636,8 @@ Return clique pointers for the given order in which they will be solved (sequent function getCliqOrderUpSolve(treel::BayesTree, startcliq=treel.cliques[1]) # http://www.geeksforgeeks.org/iterative-postorder-traversal/ # this is where we launch the downward iteration process from - parentStack = Vector{Graphs.ExVertex}() - childStack = Vector{Graphs.ExVertex}() + parentStack = Vector{TreeClique}() + childStack = Vector{TreeClique}() #Loop while first stack is not empty push!(parentStack, startcliq) # Starting at the root means we have a top down view of the tree @@ -745,7 +745,7 @@ function decodefg(fgs::FactorGraph) fgu = deepcopy(fgs) fgu.cg = nothing # will be deprecated or replaced fgu.registeredModuleFunctions = nothing # TODO: obsolete - fgu.g = Graphs.incdict(Graphs.ExVertex,is_directed=false) + fgu.g = Graphs.incdict(TreeClique,is_directed=false) @showprogress 1 "Decoding variables..." for (vsym,vid) in fgs.IDs cpvert = deepcopy(getVert(fgs, vid, api=api)) api.addvertex!(fgu, cpvert) #, labels=vnlbls) # currently losing labels @@ -782,7 +782,7 @@ function decodefg(fgs::FactorGraph) fcnode = getVert(fgu, fsym, nt=:fnc) # ccw = solverData(fcnode) ccw_jld = deepcopy(solverData(fcnode)) - allnei = Graphs.ExVertex[] + allnei = TreeClique[] for nei in out_neighbors(fcnode, fgu.g) push!(allnei, nei) data = IncrementalInference.solverData(nei) diff --git a/src/DispatchPackedConversions.jl b/src/DispatchPackedConversions.jl index 7583c34f5..d806de946 100644 --- a/src/DispatchPackedConversions.jl +++ b/src/DispatchPackedConversions.jl @@ -171,7 +171,7 @@ are used for database persistence with CloudGraphs.jl. function encodefg(fgl::G ) where G <: AbstractDFG # fgs = deepcopy(fgl) - # fgs.g = Graphs.incdict(Graphs.ExVertex,is_directed=false) + # fgs.g = Graphs.incdict(TreeClique,is_directed=false) # @showprogress 1 "Encoding variables..." for vsym in getVariableIds(fgl) diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index 6570ca7b8..9deb4bec3 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,7 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::Graphs.ExVertex) = v.attributes["data"] +getData(v::TreeClique) = v.attributes["data"] """ @@ -46,7 +46,7 @@ function setData!(f::DFGFactor, data::GenericFunctionNodeData)::Nothing return nothing end # For Bayes tree -function setData!(v::Graphs.ExVertex, data) +function setData!(v::TreeClique, data) # this is a memory gulp without replacement, old attr["data"] object is left to gc v.attributes["data"] = data nothing @@ -659,7 +659,7 @@ Notes: - used by Bayes tree clique logic. - similar method in DFG """ -function isInitialized(vert::Graphs.ExVertex)::Bool +function isInitialized(vert::TreeClique)::Bool return solverData(vert).initialized end @@ -1273,8 +1273,8 @@ function getKDE(dfg::G, lbl::Symbol) where G <: AbstractDFG end function expandEdgeListNeigh!(fgl::FactorGraph, - vertdict::Dict{Int,Graphs.ExVertex}, - edgedict::Dict{Int,Graphs.Edge{Graphs.ExVertex}}) + vertdict::Dict{Int,TreeClique}, + edgedict::Dict{Int,Graphs.Edge{TreeClique}}) #asfd for vert in vertdict for newedge in out_edges(vert[2],fgl.g) @@ -1289,8 +1289,8 @@ end # dictionary of unique vertices from edgelist function expandVertexList!(fgl::FactorGraph, - edgedict::Dict{Int,Graphs.Edge{Graphs.ExVertex}}, - vertdict::Dict{Int,Graphs.ExVertex}) + edgedict::Dict{Int,Graphs.Edge{TreeClique}}, + vertdict::Dict{Int,TreeClique}) # go through all source and target nodes for edge in edgedict @@ -1304,8 +1304,8 @@ function expandVertexList!(fgl::FactorGraph, nothing end -function edgelist2edgedict(edgelist::Array{Graphs.Edge{Graphs.ExVertex},1}) - edgedict = Dict{Int,Graphs.Edge{Graphs.ExVertex}}() +function edgelist2edgedict(edgelist::Array{Graphs.Edge{TreeClique},1}) + edgedict = Dict{Int,Graphs.Edge{TreeClique}}() for edge in edgelist edgedict[edge.index] = edge end diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index 92874e6bd..afe0765cc 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -24,8 +24,8 @@ abstract type FunctorPairwiseNH <: FunctorPairwise end # abstract type FunctorPairwiseNHMinimize <: FunctorPairwiseMinimize end # TODO -const FGG = Graphs.GenericIncidenceList{Graphs.ExVertex,Graphs.Edge{Graphs.ExVertex},Array{Graphs.ExVertex,1},Array{Array{Graphs.Edge{Graphs.ExVertex},1},1}} -const FGGdict = Graphs.GenericIncidenceList{Graphs.ExVertex,Graphs.Edge{Graphs.ExVertex},Dict{Int,Graphs.ExVertex},Dict{Int,Array{Graphs.Edge{Graphs.ExVertex},1}}} +const FGG = Graphs.GenericIncidenceList{TreeClique,Graphs.Edge{TreeClique},Array{TreeClique,1},Array{Array{Graphs.Edge{TreeClique},1},1}} +const FGGdict = Graphs.GenericIncidenceList{TreeClique,Graphs.Edge{TreeClique},Dict{Int,TreeClique},Dict{Int,Array{Graphs.Edge{TreeClique},1}}} @@ -112,7 +112,7 @@ mutable struct FactorGraph id::Int nodeIDs::Array{Int,1} # TODO -- ordering seems improved to use adj permutation -- pending merge JuliaArchive/Graphs.jl/#225 factorIDs::Array{Int,1} - bnverts::Dict{Int,Graphs.ExVertex} # TODO -- not sure if this is still used, remove + bnverts::Dict{Int,TreeClique} # TODO -- not sure if this is still used, remove bnid::Int # TODO -- not sure if this is still used dimID::Int cg @@ -126,16 +126,16 @@ mutable struct FactorGraph fifo::Vector{Symbol} qfl::Int # Quasi fixed length isfixedlag::Bool # true when adhering to qfl window size for solves - FactorGraph(;reference::NothingUnion{Dict{Symbol, Tuple{Symbol, Vector{Float64}}}}=nothing, is_directed::Bool=true ) = new(Graphs.incdict(Graphs.ExVertex,is_directed=false), - Graphs.incdict(Graphs.ExVertex,is_directed=is_directed), - # Dict{Int,Graphs.ExVertex}(), - # Dict{Int,Graphs.ExVertex}(), + FactorGraph(;reference::NothingUnion{Dict{Symbol, Tuple{Symbol, Vector{Float64}}}}=nothing, is_directed::Bool=true ) = new(Graphs.incdict(TreeClique,is_directed=false), + Graphs.incdict(TreeClique,is_directed=is_directed), + # Dict{Int,TreeClique}(), + # Dict{Int,TreeClique}(), Dict{Symbol,Int}(), Dict{Symbol,Int}(), 0, [], [], - Dict{Int,Graphs.ExVertex}(), + Dict{Int,TreeClique}(), 0, 0, nothing, diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index 9142e728d..914daed37 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -507,6 +507,8 @@ export DataLayerAPI +#TreeClique +const TreeClique = Graphs.ExVertex # TODO should be deprecated const NothingUnion{T} = Union{Nothing, T} @@ -574,7 +576,7 @@ function __init__() * Frontal, separator, and upmessages are all drawn at different intensity of red. * Downward messages not shown, as they would just be singletons of the full separator set. """ - function spyCliqMat(cliq::Graphs.ExVertex; showmsg=true, suppressprint::Bool=false) + function spyCliqMat(cliq::TreeClique; showmsg=true, suppressprint::Bool=false) mat = deepcopy(getCliqMat(cliq, showmsg=showmsg)) # TODO -- add improved visualization here, iter vs skip mat = map(Float64, mat)*2.0.-1.0 diff --git a/src/InferDimensionUtils.jl b/src/InferDimensionUtils.jl index 0501214ef..ae3766262 100644 --- a/src/InferDimensionUtils.jl +++ b/src/InferDimensionUtils.jl @@ -228,7 +228,7 @@ end Return the current dimensionality of solve for each variable in a clique. """ function getCliqVariableInferDims(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, saturate::Bool=true, fraction::Bool=true )::Dict{Symbol,Float64} where G <: AbstractDFG # @@ -254,7 +254,7 @@ end # getFactorSolvableDim # """ # function getCliqVarPossibleDim(dfg::G, -# cliq::Graphs.ExVertex, +# cliq::TreeClique, # saturate::Bool=true, # fraction::Bool=true )::Dict{Symbol, Float64} # # @@ -286,7 +286,7 @@ Related getCliqVariableMoreInitDims """ -function getCliqVariableInferredPercent(dfg::G, cliq::Graphs.ExVertex) where G <: AbstractDFG +function getCliqVariableInferredPercent(dfg::G, cliq::TreeClique) where G <: AbstractDFG # cliq variables factors vars = getCliqAllVarIds(cliq) @@ -321,7 +321,7 @@ Related getCliqVariableInferredPercent """ function getCliqVariableMoreInitDims(dfg::G, - cliq::Graphs.ExVertex ) where G <: AbstractDFG + cliq::TreeClique ) where G <: AbstractDFG # # cliq variables factors vars = getCliqAllVarIds(cliq) @@ -351,7 +351,7 @@ Related getVariableInferredDimFraction, getVariableDim, getVariableInferredDim, getVariablePossibleDim """ function isCliqFullDim(fg::G, - cliq::Graphs.ExVertex )::Bool where G <: AbstractDFG + cliq::TreeClique )::Bool where G <: AbstractDFG # # get various variable percentages red = getCliqVariableInferredPercent(fg, cliq) @@ -376,7 +376,7 @@ Related fetchCliqSolvableDims, getCliqVariableMoreInitDims, getSubFgPriorityInitOrder """ function getCliqSiblingsPriorityInitOrder(tree::BayesTree, - prnt::Graphs.ExVertex, + prnt::TreeClique, logger=ConsoleLogger() )::Vector{Int} # sibs = getChildren(tree, prnt) diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 6d740bc3b..3336154e7 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -6,14 +6,14 @@ export getVariableOrder Get the frontal variable IDs `::Int` for a given clique in a Bayes (Junction) tree. """ getCliqFrontalVarIds(cliqdata::Union{BayesTreeNodeData, PackedBayesTreeNodeData})::Vector{Symbol} = cliqdata.frontalIDs -getCliqFrontalVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqFrontalVarIds(getData(cliq)) +getCliqFrontalVarIds(cliq::TreeClique)::Vector{Symbol} = getCliqFrontalVarIds(getData(cliq)) """ $SIGNATURES Get the frontal variable IDs `::Int` for a given clique in a Bayes (Junction) tree. """ -getFrontals(cliqd::Union{Graphs.ExVertex,BayesTreeNodeData})::Vector{Symbol} = getCliqFrontalVarIds(cliqd) +getFrontals(cliqd::Union{TreeClique,BayesTreeNodeData})::Vector{Symbol} = getCliqFrontalVarIds(cliqd) """ @@ -553,7 +553,7 @@ end """ $(SIGNATURES) -Return the Graphs.ExVertex node object that represents a clique in the Bayes +Return the TreeClique node object that represents a clique in the Bayes (Junction) tree, as defined by one of the frontal variables `frt<:AbstractString`. Notes @@ -568,7 +568,7 @@ getCliq(bt::BayesTree, frt::Symbol) = bt.cliques[bt.frontals[frt]] """ $(SIGNATURES) -Return the Graphs.ExVertex node object that represents a clique in the Bayes +Return the TreeClique node object that represents a clique in the Bayes (Junction) tree, as defined by one of the frontal variables `frt<:AbstractString`. Notes @@ -636,7 +636,7 @@ end Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -getUpMsgs(cliql::Graphs.ExVertex) = getData(cliql).upMsg +getUpMsgs(cliql::TreeClique) = getData(cliql).upMsg getUpMsgs(btl::BayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) """ @@ -644,7 +644,7 @@ getUpMsgs(btl::BayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -getCliqMsgsUp(cliql::Graphs.ExVertex) = upMsg(cliql) +getCliqMsgsUp(cliql::TreeClique) = upMsg(cliql) getCliqMsgsUp(treel::BayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt)) """ @@ -661,7 +661,7 @@ end Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -getDwnMsgs(cliql::Graphs.ExVertex) = getData(cliql).dwnMsg +getDwnMsgs(cliql::TreeClique) = getData(cliql).dwnMsg getDwnMsgs(btl::BayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) """ @@ -669,7 +669,7 @@ getDwnMsgs(btl::BayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -getCliqMsgsDown(cliql::Graphs.ExVertex) = getDwnMsgs(cliql) +getCliqMsgsDown(cliql::TreeClique) = getDwnMsgs(cliql) function appendUseFcts!(usefcts, @@ -741,7 +741,7 @@ Dev Notes - Why not just do this, `ffcs = union( map(x->ls(fgl, x), frtl) )`? """ function getCliqFactorsFromFrontals(fgl::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, varlist::Vector{Symbol}; inseparator::Bool=true, unused::Bool=true, @@ -791,7 +791,7 @@ end Return `::Bool` on whether factor is a partial constraint. """ isPartial(fcf::T) where {T <: FunctorInferenceType} = :partial in fieldnames(T) -function isPartial(fct::DFGFactor) #fct::Graphs.ExVertex +function isPartial(fct::DFGFactor) #fct::TreeClique fcf = solverData(fct).fnc.usrfnc! isPartial(fcf) end @@ -803,7 +803,7 @@ Determine and set the potentials for a particular `cliq` in the Bayes (Junction) """ function setCliqPotentials!(dfg::G, bt::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; solvable::Int=1 ) where G <: AbstractDFG # varlist = getCliqVarIdsAll(cliq) @@ -833,13 +833,13 @@ end function getCliquePotentials!(dfg::G, bt::BayesTree, - cliq::Graphs.ExVertex ) where G <: AbstractDFG + cliq::TreeClique ) where G <: AbstractDFG # @warn "getCliquePotentials! deprecated, use getCliqPotentials instead." getCliqPotentials(dfg, bt, cliq) end -function cliqPotentialIDs(cliq::Graphs.ExVertex) +function cliqPotentialIDs(cliq::TreeClique) potIDs = Symbol[] for idfct in getData(cliq).potentials push!(potIDs, idfct) @@ -852,7 +852,7 @@ end Collect and returl all child clique separator variables. """ -function collectSeparators(bt::BayesTree, cliq::Graphs.ExVertex)::Vector{Symbol} +function collectSeparators(bt::BayesTree, cliq::TreeClique)::Vector{Symbol} allseps = Symbol[] for child in out_neighbors(cliq, bt.bt)#tree allseps = [allseps; getData(child).separatorIDs] @@ -866,7 +866,7 @@ end Return boolean matrix of factor by variable (row by column) associations within clique, corresponds to order presented by `getCliqFactorIds` and `getCliqAllVarIds`. """ -function getCliqAssocMat(cliq::Graphs.ExVertex) +function getCliqAssocMat(cliq::TreeClique) getData(cliq).cliqAssocMat end @@ -876,7 +876,7 @@ end Return boolean matrix of upward message singletons (i.e. marginal priors) from child cliques. Variable order corresponds to `getCliqAllVarIds`. """ -getCliqMsgMat(cliq::Graphs.ExVertex) = getData(cliq).cliqMsgMat +getCliqMsgMat(cliq::TreeClique) = getData(cliq).cliqMsgMat """ $SIGNATURES @@ -885,7 +885,7 @@ Return boolean matrix of factor variable associations for a clique, optionally including (`showmsg::Bool=true`) the upward message singletons. Variable order corresponds to `getCliqAllVarIds`. """ -function getCliqMat(cliq::Graphs.ExVertex; showmsg::Bool=true) +function getCliqMat(cliq::TreeClique; showmsg::Bool=true) assocMat = getCliqAssocMat(cliq) msgMat = getCliqMsgMat(cliq) mat = showmsg ? [assocMat;msgMat] : assocMat @@ -898,7 +898,7 @@ end Get `cliq` separator (a.k.a. conditional) variable ids`::Symbol`. """ getCliqSeparatorVarIds(cliqdata::Union{BayesTreeNodeData, PackedBayesTreeNodeData})::Vector{Symbol} = cliqdata.separatorIDs -getCliqSeparatorVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqSeparatorVarIds(getData(cliq)) +getCliqSeparatorVarIds(cliq::TreeClique)::Vector{Symbol} = getCliqSeparatorVarIds(getData(cliq)) """ $SIGNATURES @@ -906,7 +906,7 @@ getCliqSeparatorVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqSeparator Get `cliq` potentials (factors) ids`::Int`. """ getCliqFactorIds(cliqdata::BayesTreeNodeData)::Vector{Symbol} = cliqdata.potentials -getCliqFactorIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqFactorIds(getData(cliq)) +getCliqFactorIds(cliq::TreeClique)::Vector{Symbol} = getCliqFactorIds(getData(cliq)) """ $SIGNATURES @@ -917,7 +917,7 @@ Related getCliqVarIdsAll, getCliqAllFactIds, getCliqVarsWithFrontalNeighbors """ -function getCliqAllVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} +function getCliqAllVarIds(cliq::TreeClique)::Vector{Symbol} frtl = getCliqFrontalVarIds(cliq) cond = getCliqSeparatorVarIds(cliq) union(frtl,cond) @@ -937,7 +937,7 @@ Related getCliqAllVarIds """ function getCliqVarsWithFrontalNeighbors(fgl::G, - cliq::Graphs.ExVertex; + cliq::TreeClique; solvable::Int=1 ) where {G <: AbstractDFG} # frtl = getCliqFrontalVarIds(cliq) @@ -963,7 +963,7 @@ Related getCliqAllVarIds, getCliqAllFactIds """ -getCliqVarIdsAll(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqAllVarIds(cliq::Graphs.ExVertex) +getCliqVarIdsAll(cliq::TreeClique)::Vector{Symbol} = getCliqAllVarIds(cliq::TreeClique) """ $SIGNATURES @@ -977,7 +977,7 @@ Related getCliqVarIdsAll, getCliqFactors """ getCliqFactorIdsAll(cliqd::BayesTreeNodeData) = cliqd.potentials -getCliqFactorIdsAll(cliq::Graphs.ExVertex) = getCliqFactorIdsAll(getData(cliq)) +getCliqFactorIdsAll(cliq::TreeClique) = getCliqFactorIdsAll(getData(cliq)) getCliqFactorIdsAll(treel::BayesTree, frtl::Symbol) = getCliqFactorIdsAll(getCliq(treel, frtl)) const getCliqFactors = getCliqFactorIdsAll @@ -998,7 +998,7 @@ function getCliqAllFactIds(cliqd::BayesTreeNodeData) return getCliqFactorIdsAll(cliqd) end -function getCliqAllFactIds(cliq::Graphs.ExVertex) +function getCliqAllFactIds(cliq::TreeClique) @warn "getCliqAllFactIds deprecated, use getCliqFactorIdsAll instead." return getCliqFactorIdsAll(getData(cliq)) end @@ -1009,7 +1009,7 @@ end Get all `cliq` variable labels as `::Symbol`. """ -function getCliqAllVarSyms(dfg::G, cliq::Graphs.ExVertex)::Vector{Symbol} where G <: AbstractDFG +function getCliqAllVarSyms(dfg::G, cliq::TreeClique)::Vector{Symbol} where G <: AbstractDFG # Symbol[getSym(dfg, varid) for varid in getCliqAllVarIds(cliq)] @warn "deprecated getCliqAllVarSyms, use getCliqAllVarIds instead." getCliqAllVarIds(cliq) # not doing all frontals @@ -1023,7 +1023,7 @@ Return dictionary of down messages consisting of all frontal and separator belie Notes: - Fetches numerical results from `subdfg` as dictated in `cliq`. """ -function getCliqDownMsgsAfterDownSolve(subdfg::G, cliq::Graphs.ExVertex)::TempBeliefMsg where G <: AbstractDFG +function getCliqDownMsgsAfterDownSolve(subdfg::G, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG # Dict{Symbol, BallTreeDensity} # where the return msgs are contained container = TempBeliefMsg() # Dict{Symbol,BallTreeDensity}() @@ -1047,7 +1047,7 @@ Get variable ids`::Int` with prior factors associated with this `cliq`. Notes: - does not include any singleton messages from upward or downward message passing. """ -function getCliqVarIdsPriors(cliq::Graphs.ExVertex, +function getCliqVarIdsPriors(cliq::TreeClique, allids::Vector{Symbol}=getCliqAllVarIds(cliq), partials::Bool=true )::Vector{Symbol} # get ids with prior factors associated with this cliq @@ -1067,7 +1067,7 @@ end Return the number of factors associated with each variable in `cliq`. """ -getCliqNumAssocFactorsPerVar(cliq::Graphs.ExVertex)::Vector{Int} = sum(getCliqAssocMat(cliq), dims=1)[:] +getCliqNumAssocFactorsPerVar(cliq::TreeClique)::Vector{Int} = sum(getCliqAssocMat(cliq), dims=1)[:] @@ -1076,7 +1076,7 @@ getCliqNumAssocFactorsPerVar(cliq::Graphs.ExVertex)::Vector{Int} = sum(getCliqAs Get `cliq` variable IDs with singleton factors -- i.e. both in clique priors and up messages. """ -function getCliqVarSingletons(cliq::Graphs.ExVertex, +function getCliqVarSingletons(cliq::TreeClique, allids::Vector{Symbol}=getCliqAllVarIds(cliq), partials::Bool=true )::Vector{Symbol} # get incoming upward messages (known singletons) @@ -1096,7 +1096,7 @@ end Get each clique subgraph association matrix. """ -function compCliqAssocMatrices!(dfg::G, bt::BayesTree, cliq::Graphs.ExVertex) where G <: AbstractDFG +function compCliqAssocMatrices!(dfg::G, bt::BayesTree, cliq::TreeClique) where G <: AbstractDFG frtl = getCliqFrontalVarIds(cliq) cond = getCliqSeparatorVarIds(cliq) inmsgIDs = collectSeparators(bt, cliq) @@ -1146,7 +1146,7 @@ function countSkips(bt::BayesTree) return skps end -function skipThroughMsgsIDs(cliq::Graphs.ExVertex) +function skipThroughMsgsIDs(cliq::TreeClique) cliqdata = getData(cliq) numfrtl1 = floor(Int,length(cliqdata.frontalIDs)+1) condAssocMat = cliqdata.cliqAssocMat[:,numfrtl1:end] @@ -1160,7 +1160,7 @@ function skipThroughMsgsIDs(cliq::Graphs.ExVertex) return msgidx end -function directPriorMsgIDs(cliq::Graphs.ExVertex) +function directPriorMsgIDs(cliq::TreeClique) frtl = getData(cliq).frontalIDs sepr = getData(cliq).separatorIDs cols = [frtl;sepr] @@ -1175,7 +1175,7 @@ function directPriorMsgIDs(cliq::Graphs.ExVertex) return cols[vec(collect(pmSkipCols))] end -function directFrtlMsgIDs(cliq::Graphs.ExVertex) +function directFrtlMsgIDs(cliq::TreeClique) numfrtl = length(getData(cliq).frontalIDs) frntAssocMat = getData(cliq).cliqAssocMat[:,1:numfrtl] frtlMsgMat = getData(cliq).cliqMsgMat[:,1:numfrtl] @@ -1186,7 +1186,7 @@ function directFrtlMsgIDs(cliq::Graphs.ExVertex) return getData(cliq).frontalIDs[vec(collect(mab))] end -function directAssignmentIDs(cliq::Graphs.ExVertex) +function directAssignmentIDs(cliq::TreeClique) # NOTE -- old version been included in iterated variable stack assocMat = getData(cliq).cliqAssocMat msgMat = getData(cliq).cliqMsgMat @@ -1202,7 +1202,7 @@ function directAssignmentIDs(cliq::Graphs.ExVertex) # also calculate how which are conditionals end -function mcmcIterationIDs(cliq::Graphs.ExVertex) +function mcmcIterationIDs(cliq::TreeClique) mat = getCliqMat(cliq) # assocMat = getData(cliq).cliqAssocMat # msgMat = getData(cliq).cliqMsgMat @@ -1220,7 +1220,7 @@ function mcmcIterationIDs(cliq::Graphs.ExVertex) return setdiff(usset, getData(cliq).directPriorMsgIDs) end -function getCliqMatVarIdx(cliq::Graphs.ExVertex, varid::Symbol, allids=getCliqAllVarIds(cliq) ) +function getCliqMatVarIdx(cliq::TreeClique, varid::Symbol, allids=getCliqAllVarIds(cliq) ) len = length(allids) [1:len;][allids .== varid][1] end @@ -1235,7 +1235,7 @@ Notes - least number of associated factor variables earlier in list - Same as getCliqVarSolveOrderUp """ -function mcmcIterationIdsOrdered(cliq::Graphs.ExVertex) +function mcmcIterationIdsOrdered(cliq::TreeClique) # get unordered iter list alliter = mcmcIterationIDs(cliq) @@ -1281,7 +1281,7 @@ Notes - least number of associated factor variables earlier in list - Same as mcmcIterationIdsOrdered """ -function getCliqVarSolveOrderUp(cliq::Graphs.ExVertex) +function getCliqVarSolveOrderUp(cliq::TreeClique) return mcmcIterationIdsOrdered(cliq) end @@ -1296,7 +1296,7 @@ Prepare the variable IDs for nested clique Gibbs mini-batch calculations, by ass - `directFrtlMsgIDs` """ -function setCliqMCIDs!(cliq::Graphs.ExVertex) +function setCliqMCIDs!(cliq::TreeClique) getData(cliq).directPriorMsgIDs = directPriorMsgIDs(cliq) # NOTE -- directvarIDs are combined into itervarIDs @@ -1314,7 +1314,7 @@ end # post order tree traversal and build potential functions -function buildCliquePotentials(dfg::G, bt::BayesTree, cliq::Graphs.ExVertex; solvable::Int=1) where G <: AbstractDFG +function buildCliquePotentials(dfg::G, bt::BayesTree, cliq::TreeClique; solvable::Int=1) where G <: AbstractDFG for child in out_neighbors(cliq, bt.bt)#tree buildCliquePotentials(dfg, bt, child) end @@ -1332,8 +1332,8 @@ end Return a vector of child cliques to `cliq`. """ -function childCliqs(treel::BayesTree, cliq::Graphs.ExVertex) - childcliqs = Vector{Graphs.ExVertex}(undef, 0) +function childCliqs(treel::BayesTree, cliq::TreeClique) + childcliqs = Vector{TreeClique}(undef, 0) for cl in Graphs.out_neighbors(cliq, treel.bt) push!(childcliqs, cl) end @@ -1349,14 +1349,14 @@ end Return a vector of child cliques to `cliq`. """ getChildren(treel::BayesTree, frtsym::Symbol) = childCliqs(treel, frtsym) -getChildren(treel::BayesTree, cliq::Graphs.ExVertex) = childCliqs(treel, cliq) +getChildren(treel::BayesTree, cliq::TreeClique) = childCliqs(treel, cliq) """ $SIGNATURES Return a vector of all siblings to a clique, which defaults to not `inclusive` the calling `cliq`. """ -function getCliqSiblings(treel::BayesTree, cliq::Graphs.ExVertex, inclusive::Bool=false)::Vector{Graphs.ExVertex} +function getCliqSiblings(treel::BayesTree, cliq::TreeClique, inclusive::Bool=false)::Vector{TreeClique} prnt = getParent(treel, cliq) if length(prnt) > 0 allch = getChildren(treel, prnt[1]) @@ -1364,7 +1364,7 @@ function getCliqSiblings(treel::BayesTree, cliq::Graphs.ExVertex, inclusive::Boo if inclusive return allch end - sibs = Graphs.ExVertex[] + sibs = TreeClique[] for ch in allch if ch.index != cliq.index push!(sibs, ch) @@ -1378,7 +1378,7 @@ end Return `cliq`'s parent clique. """ -function parentCliq(treel::BayesTree, cliq::Graphs.ExVertex) +function parentCliq(treel::BayesTree, cliq::TreeClique) Graphs.in_neighbors(cliq, treel.bt) end function parentCliq(treel::BayesTree, frtsym::Symbol) @@ -1390,7 +1390,7 @@ end Return `cliq`'s parent clique. """ -getParent(treel::BayesTree, afrontal::Union{Symbol, Graphs.ExVertex}) = parentCliq(treel, afrontal) +getParent(treel::BayesTree, afrontal::Union{Symbol, TreeClique}) = parentCliq(treel, afrontal) """ $SIGNATURES @@ -1419,7 +1419,7 @@ end Get the `::Condition` variable for a clique, likely used for delaying state transitions in state machine solver. """ -getSolveCondition(cliq::Graphs.ExVertex) = getData(cliq).solveCondition +getSolveCondition(cliq::TreeClique) = getData(cliq).solveCondition """ diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index b08cdd377..47de37314 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -12,16 +12,16 @@ Data structure for the Bayes (Junction) tree, which is used for inference and co mutable struct BayesTree bt::BTGdict btid::Int - cliques::Dict{Int,Graphs.ExVertex} + cliques::Dict{Int,TreeClique} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} buildTime::Float64 end function emptyBayesTree() - bt = BayesTree(Graphs.inclist(Graphs.ExVertex,is_directed=true), + bt = BayesTree(Graphs.inclist(TreeClique,is_directed=true), 0, - Dict{Int,Graphs.ExVertex}(), + Dict{Int,TreeClique}(), #[], Dict{AbstractString, Int}(), Symbol[], @@ -43,9 +43,9 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem dfg::T cliqSubFg::InMemG tree::BayesTree - cliq::Graphs.ExVertex - parentCliq::Vector{Graphs.ExVertex} - childCliqs::Vector{Graphs.ExVertex} + cliq::TreeClique + parentCliq::Vector{TreeClique} + childCliqs::Vector{TreeClique} forceproceed::Bool # TODO: bad flag that must be removed by refactoring sm incremental::Bool drawtree::Bool @@ -59,9 +59,9 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem CliqStateMachineContainer{BTND}(x1::G, x2::InMemoryDFGTypes, x3::BayesTree, - x4::Graphs.ExVertex, - x5::Vector{Graphs.ExVertex}, - x6::Vector{Graphs.ExVertex}, + x4::TreeClique, + x5::Vector{TreeClique}, + x6::Vector{TreeClique}, x7::Bool, x8::Bool, x9::Bool, @@ -76,9 +76,9 @@ end function CliqStateMachineContainer(x1::G, x2::InMemoryDFGTypes, x3::BayesTree, - x4::Graphs.ExVertex, - x5::Vector{Graphs.ExVertex}, - x6::Vector{Graphs.ExVertex}, + x4::TreeClique, + x5::Vector{TreeClique}, + x6::Vector{TreeClique}, x7::Bool, x8::Bool, x9::Bool, @@ -231,7 +231,7 @@ $(TYPEDEF) mutable struct FullExploreTreeType{T, T2, T3 <:InMemoryDFGTypes} fg::T3 bt::T2 - cliq::Graphs.ExVertex + cliq::TreeClique prnt::T sendmsgs::Vector{NBPMessage} end @@ -242,7 +242,7 @@ const ExploreTreeTypeLight{T} = FullExploreTreeType{T, Nothing} function ExploreTreeType(fgl::G, btl::BayesTree, - vertl::Graphs.ExVertex, + vertl::TreeClique, prt::T, msgs::Array{NBPMessage,1} ) where {G <: AbstractDFG, T} # @@ -254,7 +254,7 @@ $(TYPEDEF) """ mutable struct MsgPassType fg::GraphsDFG - cliq::Graphs.ExVertex + cliq::TreeClique vid::Symbol # Int msgs::Array{NBPMessage,1} N::Int diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 12ff92bba..218528f04 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -64,7 +64,7 @@ Add all potentials associated with this clique and vertid to dens. function packFromLocalPotentials!(dfg::AbstractDFG, dens::Vector{BallTreeDensity}, wfac::Vector{Symbol}, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, N::Int, dbg::Bool=false )::Float64 @@ -90,7 +90,7 @@ end function packFromLocalPartials!(fgl::G, partials::Dict{Int, Vector{BallTreeDensity}}, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, N::Int, dbg::Bool=false ) where G <: AbstractDFG @@ -428,7 +428,7 @@ trasit integral -- here involving separate approximate functional convolution an product operations. """ function cliqGibbs(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, inmsgs::Array{NBPMessage,1}, N::Int, @@ -485,7 +485,7 @@ end function doFMCIteration(fgl::AbstractDFG, vsym::Symbol, - cliq::Graphs.ExVertex, + cliq::TreeClique, fmsgs, N::Int, dbg::Bool, @@ -516,7 +516,7 @@ of the stipulated proposal convolutions and products of the functional objects for tree clique `cliq`. """ function fmcmc!(fgl::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, fmsgs::Vector{NBPMessage}, lbls::Vector{Symbol}, N::Int, @@ -741,7 +741,7 @@ end function dwnPrepOutMsg(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::Array{NBPMessage,1}, d::Dict{Symbol, T}, logger=ConsoleLogger()) where {G <: AbstractDFG, T} @@ -774,7 +774,7 @@ Notes - Only update frontal variables of the clique. """ function downGibbsCliqueDensity(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::Array{NBPMessage,1}, N::Int=100, MCMCIter::Int=3, @@ -824,7 +824,7 @@ function downGibbsCliqueDensity(fg::G, return DownReturnBPType(m, mdbg, d, dwnkeepmsgs) end function downGibbsCliqueDensity(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::TempBeliefMsg, # Dict{Symbol,BallTreeDensity}, N::Int=100, MCMCIter::Int=3, @@ -854,7 +854,7 @@ end Set the color of a cliq in the Bayes (Junction) tree. """ -function setCliqDrawColor(cliq::Graphs.ExVertex, fillcolor::String)::Nothing +function setCliqDrawColor(cliq::TreeClique, fillcolor::String)::Nothing cliq.attributes["fillcolor"] = fillcolor cliq.attributes["style"] = "filled" nothing @@ -902,7 +902,7 @@ end Update cliq `cliqID` in Bayes (Juction) tree `bt` according to contents of `urt` -- intended use is to update main clique after a upward belief propagation computation has been completed per clique. """ function updateFGBT!(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, urt::UpReturnBPType; dbg::Bool=false, fillcolor::String="", @@ -953,7 +953,7 @@ Notes """ function getCliqChildMsgsUp(fg_::G, treel::BayesTree, - cliq::Graphs.ExVertex, + cliq::TreeClique, ::Type{EasyMessage} ) where G <: AbstractDFG # childmsgs = NBPMessage[] @@ -969,7 +969,7 @@ function getCliqChildMsgsUp(fg_::G, return childmsgs end -function getCliqChildMsgsUp(treel::BayesTree, cliq::Graphs.ExVertex, ::Type{BallTreeDensity}) +function getCliqChildMsgsUp(treel::BayesTree, cliq::TreeClique, ::Type{BallTreeDensity}) childmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity,Float64}}}() # Vector{Bool} for child in getChildren(treel, cliq) for (key, bel) in getUpMsgs(child) @@ -993,7 +993,7 @@ Notes - Different from down initialization messages that do calculate new values -- see `prepCliqInitMsgsDown!`. - Basically converts function `getDwnMsgs` from `Dict{Symbol,BallTreeDensity}` to `Dict{Symbol,Vector{BallTreeDensity}}`. """ -function getCliqParentMsgDown(treel::BayesTree, cliq::Graphs.ExVertex) +function getCliqParentMsgDown(treel::BayesTree, cliq::TreeClique) downmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity, Float64}}}() for prnt in getParent(treel, cliq) for (key, bel) in getDwnMsgs(prnt) @@ -1133,7 +1133,7 @@ end # """ # function doCliqInferenceUp!(fgl::FactorGraph, # treel::BayesTree, -# cliql::Graphs.ExVertex; +# cliql::TreeClique; # N::Int=100, # dbg::Bool=false, # iters::Int=3 ) @@ -1213,7 +1213,7 @@ end Return `::Bool` on whether all variables in this `cliq` are marginalzed. """ -function isCliqMarginalizedFromVars(subfg::FactorGraph, cliq::Graphs.ExVertex) +function isCliqMarginalizedFromVars(subfg::FactorGraph, cliq::TreeClique) for vert in getCliqVars(subfg, cliq) if !isMarginalized(vert) return false @@ -1227,7 +1227,7 @@ end Set the marginalized status of a clique. """ -function setCliqAsMarginalized!(cliq::Graphs.ExVertex, status::Bool) +function setCliqAsMarginalized!(cliq::TreeClique, status::Bool) if status getData(cliq).initialized = :marginalized else @@ -1286,7 +1286,7 @@ based on contents of `seeksSimilar::BayesTreeNodeData`. Notes - Used to identify and skip similar cliques (i.e. recycle computations) """ -function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeNodeData)::Graphs.ExVertex +function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeNodeData)::TreeClique # inner convenience function for returning empty clique function EMPTYCLIQ() clq = ExVertex(-1,"null") diff --git a/src/SolverUtilities.jl b/src/SolverUtilities.jl index 7a5fb8860..27c25623d 100644 --- a/src/SolverUtilities.jl +++ b/src/SolverUtilities.jl @@ -238,7 +238,7 @@ Dev Notes """ function resetCliqSolve!(dfg::G, treel::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; solveKey::Symbol=:default)::Nothing where G <: AbstractDFG # cda = getData(cliq) diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index a84a62f8a..ba4488198 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -4,9 +4,9 @@ Based on a push model from child cliques that should have already completed their computation. """ -getCliqInitUpMsgs(cliq::Graphs.ExVertex)::Dict{Int, TempBeliefMsg} = getData(cliq).upInitMsgs +getCliqInitUpMsgs(cliq::TreeClique)::Dict{Int, TempBeliefMsg} = getData(cliq).upInitMsgs -function setCliqUpInitMsgs!(cliq::Graphs.ExVertex, childid::Int, msg::TempBeliefMsg) +function setCliqUpInitMsgs!(cliq::TreeClique, childid::Int, msg::TempBeliefMsg) cd = getData(cliq) soco = getSolveCondition(cliq) lockUpStatus!(cd) @@ -20,11 +20,11 @@ function setCliqUpInitMsgs!(cliq::Graphs.ExVertex, childid::Int, msg::TempBelief nothing end -function isCliqInitialized(cliq::Graphs.ExVertex)::Bool +function isCliqInitialized(cliq::TreeClique)::Bool return getData(cliq).initialized in [:initialized; :upsolved] end -function isCliqUpSolved(cliq::Graphs.ExVertex)::Bool +function isCliqUpSolved(cliq::TreeClique)::Bool return getData(cliq).initialized == :upsolved end @@ -39,7 +39,7 @@ sequence). Notes: - sorts id for increasing number of connected factors. """ -function getCliqVarInitOrderUp(cliq::Graphs.ExVertex) +function getCliqVarInitOrderUp(cliq::TreeClique) # rules to explore dimension from one to the other? # get all variable ids and number of associated factors @@ -82,9 +82,9 @@ function getCliqVarInitOrderUp(cliq::Graphs.ExVertex) end lockUpStatus!(cdat::BayesTreeNodeData, idx::Int=1) = put!(cdat.lockUpStatus, idx) -lockUpStatus!(cliq::Graphs.ExVertex, idx::Int=1) = lockUpStatus!(getData(cliq), idx) +lockUpStatus!(cliq::TreeClique, idx::Int=1) = lockUpStatus!(getData(cliq), idx) unlockUpStatus!(cdat::BayesTreeNodeData) = take!(cdat.lockUpStatus) -unlockUpStatus!(cliq::Graphs.ExVertex) = unlockUpStatus!(getData(cliq)) +unlockUpStatus!(cliq::TreeClique) = unlockUpStatus!(getData(cliq)) function lockDwnStatus!(cdat::BayesTreeNodeData, idx::Int=1; logger=ConsoleLogger()) with_logger(logger) do @@ -118,7 +118,7 @@ Notes Dev Notes - Should be made an atomic transaction """ -function notifyCliqUpInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=ConsoleLogger()) +function notifyCliqUpInitStatus!(cliq::TreeClique, status::Symbol; logger=ConsoleLogger()) cd = getData(cliq) with_logger(logger) do tt = split(string(now()), 'T')[end] @@ -152,7 +152,7 @@ function notifyCliqUpInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=C nothing end -function notifyCliqDownInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=ConsoleLogger()) +function notifyCliqDownInitStatus!(cliq::TreeClique, status::Symbol; logger=ConsoleLogger()) cdat = getData(cliq) with_logger(logger) do @info "$(now()) $(current_task()), cliq=$(cliq.index), notifyCliqDownInitStatus! -- pre-lock, new $(cdat.initialized)-->$(status)" @@ -191,9 +191,9 @@ end Return true if clique has completed the local upward direction inference procedure. """ -isUpInferenceComplete(cliq::Graphs.ExVertex) = getData(cliq).upsolved +isUpInferenceComplete(cliq::TreeClique) = getData(cliq).upsolved -function areCliqVariablesAllInitialized(dfg::G, cliq::Graphs.ExVertex) where {G <: AbstractDFG} +function areCliqVariablesAllInitialized(dfg::G, cliq::TreeClique) where {G <: AbstractDFG} allids = getCliqAllVarIds(cliq) isallinit = true for vid in allids @@ -208,7 +208,7 @@ end Determine if this `cliq` has been fully initialized and child cliques have completed their full upward inference. """ -function isCliqReadyInferenceUp(fgl::FactorGraph, tree::BayesTree, cliq::Graphs.ExVertex) +function isCliqReadyInferenceUp(fgl::FactorGraph, tree::BayesTree, cliq::TreeClique) isallinit = areCliqVariablesAllInitialized(fgl, cliq) # check that all child cliques have also completed full up inference. @@ -223,7 +223,7 @@ end Blocking call until `cliq` upInit processes has arrived at a result. """ -function getCliqInitUpResultFromChannel(cliq::Graphs.ExVertex) +function getCliqInitUpResultFromChannel(cliq::TreeClique) status = take!(getData(cliq).initUpChannel) @info "$(current_task()) Clique $(cliq.index), dumping initUpChannel status, $status" return status @@ -245,16 +245,16 @@ Notes: - `:null` represents the first uninitialized state of a cliq. """ getCliqStatus(cliqdata::BayesTreeNodeData)::Symbol = cliqdata.initialized -getCliqStatus(cliq::Graphs.ExVertex)::Symbol = getCliqStatus(getData(cliq)) +getCliqStatus(cliq::TreeClique)::Symbol = getCliqStatus(getData(cliq)) -getCliqStatusUp(cliq::Graphs.ExVertex)::Symbol = getCliqStatus(cliq) +getCliqStatusUp(cliq::TreeClique)::Symbol = getCliqStatus(cliq) """ $SIGNATURES Set up initialization or solve status of this `cliq`. """ -function setCliqStatus!(cliq::Graphs.ExVertex, status::Symbol) +function setCliqStatus!(cliq::TreeClique, status::Symbol) getData(cliq).initialized = status end @@ -267,7 +267,7 @@ end Return true if all variables in clique are considered marginalized (and initialized). """ function areCliqVariablesAllMarginalized(subfg::AbstractDFG, - cliq::Graphs.ExVertex) + cliq::TreeClique) for vsym in getCliqAllVarIds(cliq) vert = getVariable(subfg, vsym) if !isMarginalized(vert) || !isInitialized(vert) @@ -306,7 +306,7 @@ function setTreeCliquesMarginalized!(dfg::G, end -function blockCliqUntilParentDownSolved(prnt::Graphs.ExVertex; logger=ConsoleLogger())::Nothing +function blockCliqUntilParentDownSolved(prnt::TreeClique; logger=ConsoleLogger())::Nothing # lbl = prnt.attributes["label"] @@ -335,7 +335,7 @@ end """ $SIGNATURES -Block the thread until child cliques of `prnt::Graphs.ExVertex` have finished +Block the thread until child cliques of `prnt::TreeClique` have finished attempting upward initialization -- i.e. have status result. Return `::Dict{Symbol}` indicating whether next action that should be taken for each child clique. @@ -345,7 +345,7 @@ Notes: - Can be called multiple times """ function blockCliqUntilChildrenHaveUpStatus(tree::BayesTree, - prnt::Graphs.ExVertex, + prnt::TreeClique, logger=ConsoleLogger() )::Dict{Int, Symbol} # ret = Dict{Int, Symbol}() @@ -376,7 +376,7 @@ Notes - exit strategy is parent becomes status `:initialized`. """ function blockCliqSiblingsParentNeedDown(tree::BayesTree, - cliq::Graphs.ExVertex; logger=ConsoleLogger()) + cliq::TreeClique; logger=ConsoleLogger()) # with_logger(logger) do @info "cliq $(cliq.index), blockCliqSiblingsParentNeedDown -- start of function" @@ -475,7 +475,7 @@ Update `subfg<:AbstractDFG` according to internal computations for a full upsolv """ function doCliqUpSolve!(subfg::G, tree::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; multiproc::Bool=true, logger=ConsoleLogger() )::Symbol where G <: AbstractDFG # @@ -492,7 +492,7 @@ end Prepare the upward inference messages from clique to parent and return as `Dict{Symbol}`. """ function prepCliqInitMsgsUp(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger() )::TempBeliefMsg where G <: AbstractDFG # # construct init's up msg to place in parent from initialized separator variables @@ -510,8 +510,8 @@ function prepCliqInitMsgsUp(subfg::G, return msg end -function prepCliqInitMsgsUp(subfg::G, tree::BayesTree, cliq::Graphs.ExVertex)::TempBeliefMsg where G <: AbstractDFG - @warn "deprecated, use prepCliqInitMsgsUp(subfg::FactorGraph, cliq::Graphs.ExVertex) instead" +function prepCliqInitMsgsUp(subfg::G, tree::BayesTree, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG + @warn "deprecated, use prepCliqInitMsgsUp(subfg::FactorGraph, cliq::TreeClique) instead" prepCliqInitMsgsUp(subfg, cliq) end @@ -529,7 +529,7 @@ Notes """ function doCliqAutoInitUpPart1!(subfg::G, tree::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; up_solve_if_able::Bool=true, multiproc::Bool=true, logger=ConsoleLogger() ) where {G <: AbstractDFG} @@ -572,7 +572,7 @@ Notes """ function doCliqAutoInitUpPart2!(subfg::G, tree::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; # msgfcts; up_solve_if_able::Bool=true, multiproc::Bool=true, @@ -682,8 +682,8 @@ end function condenseDownMsgsProductPrntFactors!(fgl::G, products, msgspervar, - prnt::Graphs.ExVertex, - cliq::Graphs.ExVertex, + prnt::TreeClique, + cliq::TreeClique, logger=ConsoleLogger() ) where G <: AbstractDFG # @@ -766,8 +766,8 @@ Dev Notes """ function prepCliqInitMsgsDown!(fgl::G, tree::BayesTree, - prnt::Graphs.ExVertex, - cliq::Graphs.ExVertex; + prnt::TreeClique, + cliq::TreeClique; logger=ConsoleLogger(), dbgnew::Bool=true ) where G <: AbstractDFG # @@ -851,7 +851,7 @@ Dev Notes - TODO replace with nested 'minimum degree' type variable ordering. """ function getCliqInitVarOrderDown(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, downmsgs::TempBeliefMsg )::Vector{Symbol} where G <: AbstractDFG # allsyms = getCliqAllVarIds(cliq) @@ -991,7 +991,7 @@ end Return true or false depending on whether child cliques are all up solved. """ function areCliqChildrenAllUpSolved(treel::BayesTree, - prnt::Graphs.ExVertex)::Bool + prnt::TreeClique)::Bool # for ch in getChildren(treel, prnt) if !isCliqUpSolved(ch) @@ -1032,7 +1032,7 @@ Algorithm: - can only ever return :initialized or :needdownmsg status """ function doCliqInitDown!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwinmsgs::TempBeliefMsg; dbg::Bool=false, logpath::String="/tmp/caesar/", @@ -1081,7 +1081,7 @@ end function doCliqInitDown!(subfg::G, tree::BayesTree, - cliq::Graphs.ExVertex; + cliq::TreeClique; dbg::Bool=false ) where G <: AbstractDFG # @error "deprecated doCliqInitDown!(subfg, tree, cliq) use doCliqInitDown!(subfg, cliq, dwinmsgs) instead." @@ -1098,7 +1098,7 @@ end Return `true` if any of the children cliques have status `:needdownmsg`. """ -function areCliqChildrenNeedDownMsg(children::Vector{Graphs.ExVertex})::Bool +function areCliqChildrenNeedDownMsg(children::Vector{TreeClique})::Bool for ch in children if getCliqStatus(ch) == :needdownmsg return true @@ -1107,7 +1107,7 @@ function areCliqChildrenNeedDownMsg(children::Vector{Graphs.ExVertex})::Bool return false end -function areCliqChildrenNeedDownMsg(tree::BayesTree, cliq::Graphs.ExVertex)::Bool +function areCliqChildrenNeedDownMsg(tree::BayesTree, cliq::TreeClique)::Bool areCliqChildrenNeedDownMsg( getChildren(tree, cliq) ) end @@ -1117,7 +1117,7 @@ end Return true if has parent with status `:needdownmsg`. """ -function isCliqParentNeedDownMsg(tree::BayesTree, cliq::Graphs.ExVertex, logger=ConsoleLogger()) +function isCliqParentNeedDownMsg(tree::BayesTree, cliq::TreeClique, logger=ConsoleLogger()) prnt = getParent(tree, cliq) if length(prnt) == 0 return false diff --git a/test/unittests/FactorGraph01_tests.jl b/test/unittests/FactorGraph01_tests.jl index bb3132a79..f1f9fade5 100644 --- a/test/unittests/FactorGraph01_tests.jl +++ b/test/unittests/FactorGraph01_tests.jl @@ -98,7 +98,7 @@ cliq = whichCliq(tree, :x1) # 0 -children = Graphs.ExVertex[] +children = TreeClique[] for ch in Graphs.out_neighbors(cliq, tree.bt) push!(children, ch) end From 39436d4578533ad3b5b0521c61620017c6e85eec Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 7 Jan 2020 13:29:25 +0200 Subject: [PATCH 16/57] cliq.attributes["label"] -> getLabel, setLabel --- src/CliqStateMachine.jl | 2 +- src/CliqStateMachineUtils.jl | 4 ++-- src/Deprecated.jl | 26 +++++++++++++------------- src/IncrementalInference.jl | 8 +++++++- src/JunctionTree.jl | 14 +++++++------- src/SolveTree01.jl | 10 +++++----- src/TreeBasedInitialization.jl | 2 +- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 19276ae81..783e77df0 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -11,7 +11,7 @@ function infocsm(csmc::CliqStateMachineContainer, str::A) where {A <: AbstractSt tm = string(Dates.now()) tmt = split(tm, 'T')[end] - lbl = csmc.cliq.attributes["label"] + lbl = getLabel(csmc.cliq) lbl1 = split(lbl,',')[1] cliqst = getCliqStatus(csmc.cliq) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index bae7ba8e1..aff464cbd 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -489,7 +489,7 @@ function getSiblingsDelayOrder(tree::BayesTree, cliq::TreeClique, prnt, dwinmsgs end if rows[sibidx] == minimum(rows[maxcan]) with_logger(logger) do - @info "getSiblingsDelayOrder -- FORCE DOWN INIT SOLVE ON THIS CLIQUE: $(cliq.index), $(cliq.attributes["label"])" + @info "getSiblingsDelayOrder -- FORCE DOWN INIT SOLVE ON THIS CLIQUE: $(cliq.index), $(getLabel(cliq))" end return false end @@ -571,7 +571,7 @@ function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::TreeClique, prnt, dw localsep = getCliqSeparatorVarIds(cliq) seps = Dict{Int, Vector{Symbol}}() for si in sibs - # @show si.attributes["label"] + # @show getLabel(si) mighthave = intersect(getCliqSeparatorVarIds(si), localsep) if length(mighthave) > 0 seps[si.index] = mighthave diff --git a/src/Deprecated.jl b/src/Deprecated.jl index a5f76dd87..c82c3ee07 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -298,7 +298,7 @@ end Pass NBPMessages back down the tree -- pre order tree traversal. """ function downMsgPassingRecursive(inp::ExploreTreeType{T}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false) where {T} - @info "====================== Clique $(inp.cliq.attributes["label"]) =============================" + @info "====================== Clique $(getLabel(inp.cliq)) =============================" mcmciter = inp.prnt != nothing ? 3 : 0; # skip mcmc in root on dwn pass rDDT = downGibbsCliqueDensity(inp.fg, inp.cliq, inp.sendmsgs, N, mcmciter, dbg) #dwnMsg @@ -322,26 +322,26 @@ end # post order tree traversal and build potential functions function upMsgPassingRecursive(inp::ExploreTreeType{T}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false) where {T} - @info "Start Clique $(inp.cliq.attributes["label"]) =============================" + @info "Start Clique $(getLabel(inp.cliq)) =============================" childMsgs = Array{NBPMessage,1}() outnei = out_neighbors(inp.cliq, inp.bt.bt) len = length(outnei) for child in outnei ett = ExploreTreeType(inp.fg, inp.bt, child, inp.cliq, NBPMessage[]) - @info "upMsgRec -- calling new recursive on $(ett.cliq.attributes["label"])" + @info "upMsgRec -- calling new recursive on $(getLabel(ett.cliq))" newmsgs = upMsgPassingRecursive( ett, N=N, dbg=dbg ) # newmsgs - @info "upMsgRec -- finished with $(ett.cliq.attributes["label"]), w $(keys(newmsgs.p)))" + @info "upMsgRec -- finished with $(getLabel(ett.cliq)), w $(keys(newmsgs.p)))" push!( childMsgs, newmsgs ) end - @info "====================== Clique $(inp.cliq.attributes["label"]) =============================" + @info "====================== Clique $(getLabel(inp.cliq)) =============================" ett = ExploreTreeType(inp.fg, inp.bt, inp.cliq, nothing, childMsgs) urt = upGibbsCliqueDensity(ett, N, dbg) # upmsgdict updateFGBT!(inp.fg, inp.bt, inp.cliq.index, urt, dbg=dbg, fillcolor="lightblue") drawpdf ? drawTree(inp.bt) : nothing - @info "End Clique $(inp.cliq.attributes["label"]) =============================" + @info "End Clique $(getLabel(inp.cliq)) =============================" urt.upMsgs end @@ -352,7 +352,7 @@ function downGibbsCliqueDensity(inp::ExploreTreeType{T}, logger=ConsoleLogger() ) where {T} # with_logger(logger) do - @info "=================== Iter Clique $(inp.cliq.attributes["label"]) ===========================" + @info "=================== Iter Clique $(getLabel(inp.cliq)) ===========================" end mcmciter = inp.prnt != nothing ? 3 : 0 return downGibbsCliqueDensity(inp.fg, inp.cliq, inp.sendmsgs, N, mcmciter, dbg) @@ -511,7 +511,7 @@ function prepPostOrderUpPassStacks!(bt::BayesTree, end end for child in childStack - @show child.attributes["label"] + @show getLabel(child) end nothing end @@ -536,13 +536,13 @@ function asyncProcessPostStacks!(fgl::G, end cliq = chldstk[stkcnt] gomulti = true - @info "Start Clique $(cliq.attributes["label"]) =============================" + @info "Start Clique $(getLabel(cliq)) =============================" childMsgs = Array{NBPMessage,1}() ur = nothing for child in out_neighbors(cliq, bt.bt) - @info "asyncProcessPostStacks -- $(stkcnt), cliq=$(cliq.attributes["label"]), start on child $(child.attributes["label"]) haskey=$(haskey(child.attributes, "remoteref"))" + @info "asyncProcessPostStacks -- $(stkcnt), cliq=$(getLabel(cliq)), start on child $(getLabel(child)) haskey=$(haskey(child.attributes, "remoteref"))" while !haskey(refdict, child.index) - # info("Sleeping $(cliq.attributes["label"]) on lack of remoteref from $(child.attributes["label"])") + # info("Sleeping $(getLabel(cliq)) on lack of remoteref from $(getLabel(child))") # @show child.index, keys(refdict) sleep(0.25) end @@ -559,7 +559,7 @@ function asyncProcessPostStacks!(fgl::G, push!(childMsgs, ur.upMsgs) end - @info "====================== Clique $(cliq.attributes["label"]) =============================" + @info "====================== Clique $(getLabel(cliq)) =============================" emptr = BayesTree(nothing, 0, Dict{Int,TreeClique}(), Dict{String,Int}()); pett = partialExploreTreeType(fgl, emptr, cliq, nothing, childMsgs) # bt # parent cliq pointer is not needed here, fix Graphs.jl first @@ -581,7 +581,7 @@ function asyncProcessPostStacks!(fgl::G, delete!(refdict, child.index) end - @info "End Clique $(cliq.attributes["label"]) =============================" + @info "End Clique $(getLabel(cliq)) =============================" nothing end diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index 914daed37..ee1789265 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -510,6 +510,12 @@ export #TreeClique const TreeClique = Graphs.ExVertex +DFG.getLabel(cliq::Graphs.ExVertex) = cliq.attributes["label"] +function setLabel(cliq::Graphs.ExVertex, lbl::String) + cliq.attributes["label"] = lbl + lbl +end + # TODO should be deprecated const NothingUnion{T} = Union{Nothing, T} @@ -594,7 +600,7 @@ function __init__() @show getData(cliq).directPriorMsgIDs end sp = Gadfly.spy(mat) - push!(sp.guides, Gadfly.Guide.title("$(cliq.attributes["label"]) || $(cliq.attributes["data"].frontalIDs) :$(cliq.attributes["data"].separatorIDs)")) + push!(sp.guides, Gadfly.Guide.title("$(getLabel(cliq)) || $(cliq.attributes["data"].frontalIDs) :$(cliq.attributes["data"].separatorIDs)")) push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(cliq.attributes["data"].itervarIDs)")) push!(sp.guides, Gadfly.Guide.ylabel("lcl=$(numlcl) || msg=$(size(getCliqMsgMat(cliq),1))" )) return sp diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 3336154e7..4002764ca 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -26,7 +26,7 @@ function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol} clq = Graphs.add_vertex!(bt.bt, ExVertex(bt.btid,string("Clique",bt.btid))) bt.cliques[bt.btid] = clq - clq.attributes["label"] = "" + setLabel(clq, "") # Specific data container setData!(clq, emptyBTNodeData()) @@ -51,7 +51,7 @@ function makeCliqueLabel(dfg::G, bt::BayesTree, clqID::Int)::String where G <: A for sepr in getData(clq).separatorIDs clbl = string(clbl, DFG.getVariable(dfg,sepr).label, ",") end - clq.attributes["label"] = string(flbl, ": ", clbl) + setLabel(clq, string(flbl, ": ", clbl)) end """ @@ -258,10 +258,10 @@ function drawTree(treel::BayesTree; btc = deepcopy(treel) for (cid, cliq) in btc.cliques if imgs - firstlabel = split(cliq.attributes["label"],',')[1] + firstlabel = split(getLabel(cliq),',')[1] spyCliqMat(cliq, suppressprint=true) |> exportimg("/tmp/$firstlabel.png") cliq.attributes["image"] = "/tmp/$firstlabel.png" - cliq.attributes["label"] = "" + setLabel(cliq, "") end delete!(cliq.attributes, "data") end @@ -300,7 +300,7 @@ function generateTexTree(treel::BayesTree; filepath::String="/tmp/caesar/bayes/bt") btc = deepcopy(treel) for (cid, cliq) in btc.cliques - label = cliq.attributes["label"] + label = getLabel(cliq) # Get frontals and separator, and split into elements. frt, sep = split(label,':') @@ -338,7 +338,7 @@ function generateTexTree(treel::BayesTree; newseparator = newseparator[1:end-2] # Create full label and replace the old one. newlabel = string(newfrontals, ":", newseparator) - cliq.attributes["label"] = newlabel + setLabel(cliq, newlabel) end # Use new labels to produce `.dot` and `.tex` files. @@ -1318,7 +1318,7 @@ function buildCliquePotentials(dfg::G, bt::BayesTree, cliq::TreeClique; solvable for child in out_neighbors(cliq, bt.bt)#tree buildCliquePotentials(dfg, bt, child) end - @info "Get potentials $(cliq.attributes["label"])" + @info "Get potentials $(getLabel(cliq))" setCliqPotentials!(dfg, bt, cliq, solvable=solvable) compCliqAssocMatrices!(dfg, bt, cliq) diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 218528f04..3819a34ea 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -526,7 +526,7 @@ function fmcmc!(fgl::G, multithreaded::Bool=false ) where G <: AbstractDFG # with_logger(logger) do - @info "---------- successive fnc approx ------------$(cliq.attributes["label"])" + @info "---------- successive fnc approx ------------$(getLabel(cliq))" end # repeat several iterations of functional Gibbs sampling for fixed point convergence if length(lbls) == 1 @@ -926,7 +926,7 @@ function updateFGBT!(fg::G, setValKDE!(updvert, deepcopy(dat), true) ## TODO -- not sure if deepcopy is required end with_logger(logger) do - @info "updateFGBT! up -- updated $(cliq.attributes["label"])" + @info "updateFGBT! up -- updated $(getLabel(cliq))" end nothing end @@ -1056,7 +1056,7 @@ function approxCliqMarginalUp!(fgl::G, # TODO use subgraph copy of factor graph for operations and transfer frontal variables only with_logger(logger) do - @info "=== start Clique $(cliq.attributes["label"]) ======================" + @info "=== start Clique $(getLabel(cliq)) ======================" end ett = FullExploreTreeType(fg_, nothing, cliq, nothing, childmsgs) urt = UpReturnBPType() @@ -1093,7 +1093,7 @@ function approxCliqMarginalUp!(fgl::G, drawpdf ? drawTree(tree_) : nothing with_logger(logger) do - @info "=== end Clique $(cliq.attributes["label"]) ========================" + @info "=== end Clique $(getLabel(cliq)) ========================" end return urt end @@ -1290,7 +1290,7 @@ function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeN # inner convenience function for returning empty clique function EMPTYCLIQ() clq = ExVertex(-1,"null") - clq.attributes["label"] = "" + setLabel(clq, "") setData!(clq, emptyBTNodeData()) return clq end diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index ba4488198..40b78731d 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -308,7 +308,7 @@ end function blockCliqUntilParentDownSolved(prnt::TreeClique; logger=ConsoleLogger())::Nothing # - lbl = prnt.attributes["label"] + lbl = getLabel(prnt) with_logger(logger) do @info "blockCliqUntilParentDownSolved, prntcliq=$(prnt.index) | $lbl | going to fetch initdownchannel..." From a02d96c6e094e1862457835fa78823ab4158b4d1 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 7 Jan 2020 14:16:45 +0200 Subject: [PATCH 17/57] remaning attributes["data"] -> getData setData --- src/FactorGraph01.jl | 8 ++++---- src/IncrementalInference.jl | 4 ++-- src/JunctionTree.jl | 17 ++++++++--------- src/SolveTree01.jl | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index 9deb4bec3..e8ddb6f1c 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,7 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::TreeClique) = v.attributes["data"] +getData(v::Graphs.ExVertex) = v.attributes["data"] """ @@ -46,7 +46,7 @@ function setData!(f::DFGFactor, data::GenericFunctionNodeData)::Nothing return nothing end # For Bayes tree -function setData!(v::TreeClique, data) +function setData!(v::Graphs.ExVertex, data) # this is a memory gulp without replacement, old attr["data"] object is left to gc v.attributes["data"] = data nothing @@ -1115,7 +1115,7 @@ end function addConditional!(dfg::AbstractDFG, vertId::Symbol, Si::Vector{Symbol})::Nothing bnv = DFG.getVariable(dfg, vertId) - bnvd = solverData(bnv) # bnv.attributes["data"] + bnvd = solverData(bnv) bnvd.separator = Si for s in Si push!(bnvd.BayesNetOutVertIDs, s) @@ -1198,7 +1198,7 @@ function buildBayesNet!(dfg::G, push!(Si,sepNode) end end - solverData(fct).eliminated = true #fct.attributes["data"].eliminated = true + solverData(fct).eliminated = true end if typeof(solverData(fct).fnc) == CommonConvWrapper{GenericMarginal} diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index ee1789265..a3b09b66e 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -600,8 +600,8 @@ function __init__() @show getData(cliq).directPriorMsgIDs end sp = Gadfly.spy(mat) - push!(sp.guides, Gadfly.Guide.title("$(getLabel(cliq)) || $(cliq.attributes["data"].frontalIDs) :$(cliq.attributes["data"].separatorIDs)")) - push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(cliq.attributes["data"].itervarIDs)")) + push!(sp.guides, Gadfly.Guide.title("$(getLabel(cliq)) || $(getData(cliq).frontalIDs) :$(getData(cliq).separatorIDs)")) + push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(getData(cliq).itervarIDs)")) push!(sp.guides, Gadfly.Guide.ylabel("lcl=$(numlcl) || msg=$(size(getCliqMsgMat(cliq),1))" )) return sp end diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 4002764ca..fb11d2aca 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -30,7 +30,6 @@ function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol} # Specific data container setData!(clq, emptyBTNodeData()) - # clq.attributes["data"] = emptyBTNodeData() appendClique!(bt, bt.btid, dfg, varID, condIDs) return clq @@ -1512,8 +1511,8 @@ function saveTree(treel::BayesTree, # savetree = deepcopy(treel) for i in 1:length(savetree.cliques) - if savetree.cliques[i].attributes["data"] isa BayesTreeNodeData - savetree.cliques[i].attributes["data"] = convert(PackedBayesTreeNodeData, savetree.cliques[i].attributes["data"]) + if getData(savetree.cliques[i]) isa BayesTreeNodeData + setData!(savetree.cliques[i], convert(PackedBayesTreeNodeData, getData(savetree.cliques[i]))) end end @@ -1526,8 +1525,8 @@ function saveTree(treeArr::Vector{BayesTree}, # savetree = deepcopy(treeArr) for savtre in savetree, i in 1:length(savtre.cliques) - if savtre.cliques[i].attributes["data"] isa BayesTreeNodeData - savtre.cliques[i].attributes["data"] = convert(PackedBayesTreeNodeData, savtre.cliques[i].attributes["data"]) + if getData(savtre.cliques[i]) isa BayesTreeNodeData + setData!(savtre.cliques[i], convert(PackedBayesTreeNodeData, getData(savtre.cliques[i]))) end end @@ -1554,14 +1553,14 @@ function loadTree(filepath=joinpath("/tmp","caesar","savetree.jld2")) # convert back to a type that which could not be serialized by JLD2 if savetree isa Vector for savtre in savetree, i in 1:length(savtre.cliques) - if savtre.cliques[i].attributes["data"] isa PackedBayesTreeNodeData - savtre.cliques[i].attributes["data"] = convert(BayesTreeNodeData, savtre.cliques[i].attributes["data"]) + if getData(savtre.cliques[i]) isa PackedBayesTreeNodeData + setData!(savtre.cliques[i], convert(BayesTreeNodeData, getData(savtre.cliques[i]))) end end else for i in 1:length(savetree.cliques) - if savetree.cliques[i].attributes["data"] isa PackedBayesTreeNodeData - savetree.cliques[i].attributes["data"] = convert(BayesTreeNodeData, savetree.cliques[i].attributes["data"]) + if getData(savetree.cliques[i]) isa PackedBayesTreeNodeData + setData!(savetree.cliques[i], convert(BayesTreeNodeData, getData(savetree.cliques[i]))) end end end diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 3819a34ea..bedce42f7 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -854,7 +854,7 @@ end Set the color of a cliq in the Bayes (Junction) tree. """ -function setCliqDrawColor(cliq::TreeClique, fillcolor::String)::Nothing +function setCliqDrawColor(cliq::Graphs.ExVertex, fillcolor::String)::Nothing cliq.attributes["fillcolor"] = fillcolor cliq.attributes["style"] = "filled" nothing From 90fe3eeca966d31175168b13cc95ac2192817a3a Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Tue, 7 Jan 2020 14:46:44 +0200 Subject: [PATCH 18/57] WIP MetaBayesTree --- src/JunctionTreeTypes.jl | 61 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 47de37314..755819ceb 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -1,4 +1,6 @@ +using MetaGraphs +abstract type AbstractBayesTree end const BTGdict = GenericIncidenceList{ExVertex,Edge{ExVertex},Array{ExVertex,1},Array{Array{Edge{ExVertex},1},1}} @@ -9,10 +11,10 @@ $(TYPEDEF) Data structure for the Bayes (Junction) tree, which is used for inference and constructed from a given `::FactorGraph`. """ -mutable struct BayesTree +mutable struct BayesTree <: AbstractBayesTree bt::BTGdict btid::Int - cliques::Dict{Int,TreeClique} + cliques::Dict{Int,Graphs.ExVertex} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} buildTime::Float64 @@ -30,6 +32,61 @@ function emptyBayesTree() end +# TODO DEV MetaGraphs bayes tree +""" +$(TYPEDEF) +Data structure for the Bayes (Junction) tree, which is used for inference and constructed from a given `::FactorGraph`. +""" +mutable struct MetaBayesTree <: AbstractBayesTree + bt::MetaDiGraph{Int,Float64} + btid::Int + # cliques::Dict{Int,Graphs.ExVertex} + frontals::Dict{Symbol,Int} + variableOrder::Vector{Symbol} + buildTime::Float64 +end + +MetaBayesTree() = MetaBayesTree(MetaDiGraph{Int,Float64}(), 0, Dict{AbstractString, Int}(), Symbol[], 0.0) + +Base.propertynames(x::MetaBayesTree, private::Bool=false) = (:bt, :btid, :cliques, :frontals, :variableOrder, :buildTime) + +Base.getproperty(x::MetaBayesTree,f::Symbol) = begin + if f == :cliques + @warn "Moet die dalk nie gebruik nie" + # for (key,value) in x.bt.vprops + # + # end + x.bt.vprops + else + getfield(x,f) + end + end + +function MetaBayesTree(tree::BayesTree) + # create graph from Graphs.jl adjacency_matrix + mtree = MetaBayesTree(MetaDiGraph{Int, Float64}(MetaGraphs.SimpleDiGraph(Graphs.adjacency_matrix(tree.bt))), tree.btid, tree.frontals) + + #deep copy over properties + for v in tree.bt.vertices + set_prop!(mtree.bt, v.index, :label, deepcopy(v.attributes["label"])) + set_prop!(mtree.bt, v.index, :data, deepcopy(v.attributes["data"])) + set_prop!(mtree.bt, v.index, :attributes, Dict{String,Any}()) + end + + ## TODO: placeholder for edge stored Channels + ## set message passing properties, + # for e in MetaGraphs.edges(mtree.bt) + # set_prop!(mtree.bt, e, :upMsg, Channel{BelieveMessage}(0)) + # set_prop!(mtree.bt, e, :downMsg, Channel{BelieveMessage}(0)) + # end + + return mtree + +end + +# abstract type AbstractBayesTreeNodeData end + + """ $TYPEDEF From 934c6a6ec86348d61ec0ff84191cbb3452b64919 Mon Sep 17 00:00:00 2001 From: dehann Date: Wed, 8 Jan 2020 06:30:31 -0500 Subject: [PATCH 19/57] adjust test tolernance simplification related to #525 --- test/testBasicGraphs.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testBasicGraphs.jl b/test/testBasicGraphs.jl index 7b9d50bc8..fa5e4a27c 100644 --- a/test/testBasicGraphs.jl +++ b/test/testBasicGraphs.jl @@ -128,8 +128,8 @@ tree, smt, hist = solveTree!(fg) @test (getKDE(fg, :x0) |> getKDEMean .|> abs)[1] < 0.6 @test (getKDE(fg, :x1) |> getKDEMean .|> abs)[1] < 0.6 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 1.8 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 1.8 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 2.2 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 2.3 end From 88a1d356ac1012e1ad29d1c880b5dd0e3d11378d Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Wed, 8 Jan 2020 14:42:38 +0200 Subject: [PATCH 20/57] Change ExVertex type to TreeClique type --- Project.toml | 2 + src/CanonicalGraphExamples.jl | 70 +++++++++++++++++++++++++++++++- src/Deprecated.jl | 4 +- src/DispatchPackedConversions.jl | 2 +- src/FactorGraph01.jl | 4 +- src/FactorGraphTypes.jl | 16 ++++---- src/IncrementalInference.jl | 11 +---- src/JunctionTree.jl | 18 ++++---- src/JunctionTreeTypes.jl | 40 ++++++++++++++---- src/SolveTree01.jl | 6 +-- test/runtests.jl | 3 +- 11 files changed, 131 insertions(+), 45 deletions(-) diff --git a/Project.toml b/Project.toml index e53ad338d..a4cc92a20 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,7 @@ JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" KernelDensityEstimate = "2472808a-b354-52ea-a80e-1658a3c6056d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" Optim = "429524aa-4258-5aef-a3af-852621145aeb" ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" @@ -42,6 +43,7 @@ Graphs = "0.10.2, 0.11, 1" JLD2 = "0.1, 0.2, 0.3, 1.0" JSON2 = "0.3, 0.4, 0.5, 0.6, 0.7, 1" KernelDensityEstimate = "0.5.1, 0.6" +MetaGraphs = "0.6.4" NLsolve = "3, 4" Optim = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23 1" ProgressMeter = "0.6, 0.7, 0.8, 0.9, 1" diff --git a/src/CanonicalGraphExamples.jl b/src/CanonicalGraphExamples.jl index 8892e2865..a9c332e83 100644 --- a/src/CanonicalGraphExamples.jl +++ b/src/CanonicalGraphExamples.jl @@ -1,6 +1,5 @@ -export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D - +export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D, lineStepFG """ $SIGNATURES @@ -104,3 +103,70 @@ function loadCanonicalFG_CaesarRing1D(;graphinit::Bool=false) return fg end + + + +""" + $SIGNATURES +Continuous, linear scalar and multivariate test graph generation. Follows a line +with the pose id equal to the ground truth. +""" +function generateCanonicalFG_lineStep(lineLength::Int; + poseEvery::Int=2, + landmarkEvery::Int=4, + posePriorsAt = Int[0], + landmarkPriorsAt = Int[], + sightDistance::Int=4, + vardims = 1, + noisy = false, + graphinit = false, + σ_pose_prior = 1.0, + σ_lm_prior = 1.0, + σ_pose_pose = 1.0, + σ_pose_lm = 1.0, + params=SolverParams()) + # params=SolverParams(algorithms=[:default, :parametric])) + + vtype = (vardims == 1) ? ContinuousScalar() : ContinuousMultivariate(vardims) + + fg = LightDFG{SolverParams}( params=params) + # fg = GraphsDFG{SolverParams}( params=params) + + function xNoise(i::Int, σ::Float64=1.0) + if (vardims == 1) + return noisy ? Normal(σ*randn() + i, σ) : Normal(0.0*randn() + i, σ) + else + return noisy ? MvNormal(σ*randn(vardims) .+ i, σ) : MvNormal(0.0*randn(vardims) .+ i, σ) + end + end + + x = Int[] + lm = Int[] + for i=0:lineLength + if mod(i,poseEvery) == 0 + push!(x, i) + addVariable!(fg, Symbol("x",i), vtype, autoinit = graphinit) + (i in posePriorsAt) && addFactor!(fg, [Symbol("x",i)], Prior(xNoise(i, σ_pose_prior))) + # "odo" type + (i > 0) && addFactor!(fg, [Symbol("x",i-poseEvery); Symbol("x",i)], LinearConditional(xNoise(poseEvery, σ_pose_pose))) + end + + + if landmarkEvery != 0 && mod(i,landmarkEvery) == 0 + push!(lm, i) + addVariable!(fg, Symbol("lm",i), vtype, autoinit = graphinit) + (i in landmarkPriorsAt) && addFactor!(fg, [Symbol("lm",i)], Prior(xNoise(i, σ_lm_prior))) + end + end + + #add landmarks sightings + for xi in x, lmi in lm + dist = lmi - xi + if abs(dist) < sightDistance + # @info "adding landmark lm$lmi to x$xi with dist $dist" + addFactor!(fg, [Symbol("x",xi); Symbol("lm",lmi)], LinearConditional(xNoise(dist, σ_pose_lm))) + end + end + + return fg +end diff --git a/src/Deprecated.jl b/src/Deprecated.jl index c82c3ee07..6848f7c08 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -519,7 +519,7 @@ end """ $SIGNATURES -Asynchronously perform up message passing, based on previoulsy prepared `chldstk::Vector{ExVertex}`. +Asynchronously perform up message passing, based on previoulsy prepared `chldstk::Vector{TreeClique}`. """ function asyncProcessPostStacks!(fgl::G, bt::BayesTree, @@ -756,7 +756,7 @@ function decodefg(fgs::FactorGraph) data = decodePackedType(fdata, "") # data = FunctionNodeData{ftyp}(Int[], false, false, Int[], m, gwpf) - newvert = ExVertex(fid,string(fsym)) + newvert = TreeClique(fid,string(fsym)) for (key,val) in getVert(fgs,fid,api=api).attributes newvert.attributes[key] = val end diff --git a/src/DispatchPackedConversions.jl b/src/DispatchPackedConversions.jl index d806de946..3c24e243a 100644 --- a/src/DispatchPackedConversions.jl +++ b/src/DispatchPackedConversions.jl @@ -184,7 +184,7 @@ function encodefg(fgl::G ) where G <: AbstractDFG for (fsym,fid) in fgs.fIDs data,ftyp = convert2packedfunctionnode(fgl, fsym) data = FunctionNodeData{ftyp}(Int[], false, false, Int[], m, gwpf) - # newvert = ExVertex(fid,string(fsym)) + # newvert = TreeClique(fid,string(fsym)) # for (key,val) in getVert(fgl,fid,api=api).attributes # newvert.attributes[key] = val # end diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index e8ddb6f1c..68657785e 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,7 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::Graphs.ExVertex) = v.attributes["data"] +getData(v::TreeClique) = v.attributes["data"] """ @@ -46,7 +46,7 @@ function setData!(f::DFGFactor, data::GenericFunctionNodeData)::Nothing return nothing end # For Bayes tree -function setData!(v::Graphs.ExVertex, data) +function setData!(v::TreeClique, data) # this is a memory gulp without replacement, old attr["data"] object is left to gc v.attributes["data"] = data nothing diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index afe0765cc..92874e6bd 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -24,8 +24,8 @@ abstract type FunctorPairwiseNH <: FunctorPairwise end # abstract type FunctorPairwiseNHMinimize <: FunctorPairwiseMinimize end # TODO -const FGG = Graphs.GenericIncidenceList{TreeClique,Graphs.Edge{TreeClique},Array{TreeClique,1},Array{Array{Graphs.Edge{TreeClique},1},1}} -const FGGdict = Graphs.GenericIncidenceList{TreeClique,Graphs.Edge{TreeClique},Dict{Int,TreeClique},Dict{Int,Array{Graphs.Edge{TreeClique},1}}} +const FGG = Graphs.GenericIncidenceList{Graphs.ExVertex,Graphs.Edge{Graphs.ExVertex},Array{Graphs.ExVertex,1},Array{Array{Graphs.Edge{Graphs.ExVertex},1},1}} +const FGGdict = Graphs.GenericIncidenceList{Graphs.ExVertex,Graphs.Edge{Graphs.ExVertex},Dict{Int,Graphs.ExVertex},Dict{Int,Array{Graphs.Edge{Graphs.ExVertex},1}}} @@ -112,7 +112,7 @@ mutable struct FactorGraph id::Int nodeIDs::Array{Int,1} # TODO -- ordering seems improved to use adj permutation -- pending merge JuliaArchive/Graphs.jl/#225 factorIDs::Array{Int,1} - bnverts::Dict{Int,TreeClique} # TODO -- not sure if this is still used, remove + bnverts::Dict{Int,Graphs.ExVertex} # TODO -- not sure if this is still used, remove bnid::Int # TODO -- not sure if this is still used dimID::Int cg @@ -126,16 +126,16 @@ mutable struct FactorGraph fifo::Vector{Symbol} qfl::Int # Quasi fixed length isfixedlag::Bool # true when adhering to qfl window size for solves - FactorGraph(;reference::NothingUnion{Dict{Symbol, Tuple{Symbol, Vector{Float64}}}}=nothing, is_directed::Bool=true ) = new(Graphs.incdict(TreeClique,is_directed=false), - Graphs.incdict(TreeClique,is_directed=is_directed), - # Dict{Int,TreeClique}(), - # Dict{Int,TreeClique}(), + FactorGraph(;reference::NothingUnion{Dict{Symbol, Tuple{Symbol, Vector{Float64}}}}=nothing, is_directed::Bool=true ) = new(Graphs.incdict(Graphs.ExVertex,is_directed=false), + Graphs.incdict(Graphs.ExVertex,is_directed=is_directed), + # Dict{Int,Graphs.ExVertex}(), + # Dict{Int,Graphs.ExVertex}(), Dict{Symbol,Int}(), Dict{Symbol,Int}(), 0, [], [], - Dict{Int,TreeClique}(), + Dict{Int,Graphs.ExVertex}(), 0, 0, nothing, diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index a3b09b66e..dc904dcb7 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -507,15 +507,6 @@ export DataLayerAPI -#TreeClique -const TreeClique = Graphs.ExVertex - -DFG.getLabel(cliq::Graphs.ExVertex) = cliq.attributes["label"] -function setLabel(cliq::Graphs.ExVertex, lbl::String) - cliq.attributes["label"] = lbl - lbl -end - # TODO should be deprecated const NothingUnion{T} = Union{Nothing, T} @@ -531,13 +522,13 @@ const InMemDFGType = DFG.GraphsDFG{SolverParams} # JT TODO move to somewhere mor include("BeliefTypes.jl") include("AliasScalarSampling.jl") include("DefaultNodeTypes.jl") +include("JunctionTreeTypes.jl") include("FactorGraph01.jl") include("SerializingDistributions.jl") include("DispatchPackedConversions.jl") include("FGOSUtils.jl") include("CompareUtils.jl") -include("JunctionTreeTypes.jl") include("SubGraphFunctions.jl") include("JunctionTree.jl") include("TreeBasedInitialization.jl") diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index fb11d2aca..14e7e2446 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -21,12 +21,12 @@ getFrontals(cliqd::Union{TreeClique,BayesTreeNodeData})::Vector{Symbol} = getCli Create a new clique. """ -function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::ExVertex where G <: AbstractDFG +function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::TreeClique where G <: AbstractDFG bt.btid += 1 - clq = Graphs.add_vertex!(bt.bt, ExVertex(bt.btid,string("Clique",bt.btid))) + clq = Graphs.add_vertex!(bt.bt, TreeClique(bt.btid,string("Clique",bt.btid))) bt.cliques[bt.btid] = clq - setLabel(clq, "") + setLabel!(clq, "") # Specific data container setData!(clq, emptyBTNodeData()) @@ -50,7 +50,7 @@ function makeCliqueLabel(dfg::G, bt::BayesTree, clqID::Int)::String where G <: A for sepr in getData(clq).separatorIDs clbl = string(clbl, DFG.getVariable(dfg,sepr).label, ",") end - setLabel(clq, string(flbl, ": ", clbl)) + setLabel!(clq, string(flbl, ": ", clbl)) end """ @@ -260,7 +260,7 @@ function drawTree(treel::BayesTree; firstlabel = split(getLabel(cliq),',')[1] spyCliqMat(cliq, suppressprint=true) |> exportimg("/tmp/$firstlabel.png") cliq.attributes["image"] = "/tmp/$firstlabel.png" - setLabel(cliq, "") + setLabel!(cliq, "") end delete!(cliq.attributes, "data") end @@ -337,7 +337,7 @@ function generateTexTree(treel::BayesTree; newseparator = newseparator[1:end-2] # Create full label and replace the old one. newlabel = string(newfrontals, ":", newseparator) - setLabel(cliq, newlabel) + setLabel!(cliq, newlabel) end # Use new labels to produce `.dot` and `.tex` files. @@ -616,12 +616,12 @@ Set the upward passing message for Bayes (Junction) tree clique `cliql`. Dev Notes - TODO setUpMsg! should also set inferred dimension """ -function setUpMsg!(cliql::ExVertex, msgs::Dict{Symbol, BallTreeDensity}) +function setUpMsg!(cliql::TreeClique, msgs::Dict{Symbol, BallTreeDensity}) @error "setUpMsg!, use inferred dimension version instead" getData(cliql).upMsg = msgs end -function setUpMsg!(cliql::ExVertex, msgs::TempBeliefMsg) #Dict{Symbol, Tuple{BallTreeDensity, Float64}} +function setUpMsg!(cliql::TreeClique, msgs::TempBeliefMsg) #Dict{Symbol, Tuple{BallTreeDensity, Float64}} # ms = Dict{Symbol, BallTreeDensity}() # for (id, val) in msgs # ms[id] = val[1] @@ -651,7 +651,7 @@ getCliqMsgsUp(treel::BayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt) Set the downward passing message for Bayes (Junction) tree clique `cliql`. """ -function setDwnMsg!(cliql::ExVertex, msgs::TempBeliefMsg) #Dict{Symbol, BallTreeDensity} +function setDwnMsg!(cliql::TreeClique, msgs::TempBeliefMsg) #Dict{Symbol, BallTreeDensity} getData(cliql).dwnMsg = msgs end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 755819ceb..5fcfd6ec6 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -1,9 +1,36 @@ using MetaGraphs -abstract type AbstractBayesTree end +## Cliques + +""" + $(TYPEDEF) +Structure to store clique data +DEV NOTES: To replace TreeClique completely + $(FIELDS) +""" +mutable struct TreeClique + index::Int + label::Symbol + data::Any #BayesTreeNodeData #FIXME There is a circular types for BayesTreeNodeData -> CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 + attributes::Dict{String, Any} +end + +TreeClique(i::Int, label::Symbol) = TreeClique(i, label, emptyBTNodeData(), Dict{String,Any}("label"=>label)) +TreeClique(i::Int, label::AbstractString) = TreeClique(i, Symbol(label)) +DFG.getLabel(cliq::TreeClique) = cliq.attributes["label"] +function setLabel!(cliq::TreeClique, lbl::String) + cliq.attributes["label"] = lbl + lbl +end + +## end Cliques + +## Bayes Trees -const BTGdict = GenericIncidenceList{ExVertex,Edge{ExVertex},Array{ExVertex,1},Array{Array{Edge{ExVertex},1},1}} +abstract type AbstractBayesTree end + +const BTGdict = GenericIncidenceList{TreeClique,Edge{TreeClique},Array{TreeClique,1},Array{Array{Edge{TreeClique},1},1}} # BayesTree declarations """ @@ -14,7 +41,7 @@ Data structure for the Bayes (Junction) tree, which is used for inference and co mutable struct BayesTree <: AbstractBayesTree bt::BTGdict btid::Int - cliques::Dict{Int,Graphs.ExVertex} + cliques::Dict{Int,TreeClique} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} buildTime::Float64 @@ -32,7 +59,7 @@ function emptyBayesTree() end -# TODO DEV MetaGraphs bayes tree +# TODO DEV MetaGraphs bayes tree, will potentially also make a LightBayesTree, CloudBayesTree, """ $(TYPEDEF) Data structure for the Bayes (Junction) tree, which is used for inference and constructed from a given `::FactorGraph`. @@ -40,7 +67,7 @@ Data structure for the Bayes (Junction) tree, which is used for inference and co mutable struct MetaBayesTree <: AbstractBayesTree bt::MetaDiGraph{Int,Float64} btid::Int - # cliques::Dict{Int,Graphs.ExVertex} + # cliques::Dict{Int,TreeClique} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} buildTime::Float64 @@ -64,7 +91,7 @@ Base.getproperty(x::MetaBayesTree,f::Symbol) = begin function MetaBayesTree(tree::BayesTree) # create graph from Graphs.jl adjacency_matrix - mtree = MetaBayesTree(MetaDiGraph{Int, Float64}(MetaGraphs.SimpleDiGraph(Graphs.adjacency_matrix(tree.bt))), tree.btid, tree.frontals) + mtree = MetaBayesTree(MetaDiGraph{Int, Float64}(MetaGraphs.SimpleDiGraph(Graphs.adjacency_matrix(tree.bt))), tree.btid, tree.frontals, tree.variableOrder, tree.buildTime) #deep copy over properties for v in tree.bt.vertices @@ -151,7 +178,6 @@ end const CSMHistory = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}} - """ $(TYPEDEF) diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index bedce42f7..bc20d6e7a 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -854,7 +854,7 @@ end Set the color of a cliq in the Bayes (Junction) tree. """ -function setCliqDrawColor(cliq::Graphs.ExVertex, fillcolor::String)::Nothing +function setCliqDrawColor(cliq::TreeClique, fillcolor::String)::Nothing cliq.attributes["fillcolor"] = fillcolor cliq.attributes["style"] = "filled" nothing @@ -1289,8 +1289,8 @@ Notes function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeNodeData)::TreeClique # inner convenience function for returning empty clique function EMPTYCLIQ() - clq = ExVertex(-1,"null") - setLabel(clq, "") + clq = TreeClique(-1,"null") + setLabel!(clq, "") setData!(clq, emptyBTNodeData()) return clq end diff --git a/test/runtests.jl b/test/runtests.jl index ac1c6c8a1..a866d4fad 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,7 +24,8 @@ include("testPartialFactors.jl") include("testBayesTreeiSAM2Example.jl") end -include("testTreeSaveLoad.jl") +#FIXME +# include("testTreeSaveLoad.jl") @testset "Ensure converter types can be run from extending namespaces..." begin include("saveconvertertypes.jl") From 3b8e651952772381ac7377e1474240b012d3a9ff Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Wed, 8 Jan 2020 16:05:20 +0200 Subject: [PATCH 21/57] fix testTreeSaveLoad test --- src/CanonicalGraphExamples.jl | 2 +- src/FactorGraph01.jl | 5 +++-- src/JunctionTreeTypes.jl | 27 +++++++++++++-------------- test/runtests.jl | 3 +-- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/CanonicalGraphExamples.jl b/src/CanonicalGraphExamples.jl index a9c332e83..f065493d5 100644 --- a/src/CanonicalGraphExamples.jl +++ b/src/CanonicalGraphExamples.jl @@ -1,5 +1,5 @@ -export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D, lineStepFG +export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D, generateCanonicalFG_lineStep """ $SIGNATURES diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index 68657785e..cd20a2790 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,7 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::TreeClique) = v.attributes["data"] +getData(v::TreeClique) = v.data #v.attributes["data"] """ @@ -48,7 +48,8 @@ end # For Bayes tree function setData!(v::TreeClique, data) # this is a memory gulp without replacement, old attr["data"] object is left to gc - v.attributes["data"] = data + # v.attributes["data"] = data + v.data = data nothing end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 8f32495dd..ccfbb1951 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -11,13 +11,18 @@ DEV NOTES: To replace TreeClique completely mutable struct TreeClique index::Int label::Symbol - data::Any #BayesTreeNodeData #FIXME There is a circular types for BayesTreeNodeData -> CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 - attributes::Dict{String, Any} + data::Any #BayesTreeNodeData #FIXME There is circular type usage in TreeClique, BayesTreeNodeData, CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 + attributes::Dict{String, Any} #The drawing attributes end -TreeClique(i::Int, label::Symbol) = TreeClique(i, label, emptyBTNodeData(), Dict{String,Any}("label"=>label)) +TreeClique(i::Int, label::Symbol) = TreeClique(i, label, emptyBTNodeData(), Dict{String,Any}()) TreeClique(i::Int, label::AbstractString) = TreeClique(i, Symbol(label)) +Graphs.make_vertex(g::AbstractGraph{TreeClique}, label::AbstractString) = TreeClique(num_vertices(g) + 1, String(label)) +Graphs.vertex_index(v::TreeClique) = v.index +Graphs.attributes(v::TreeClique, g::AbstractGraph) = v.attributes + +#TODO the label field and label atribute is a bit confusing with accessors. DFG.getLabel(cliq::TreeClique) = cliq.attributes["label"] function setLabel!(cliq::TreeClique, lbl::String) cliq.attributes["label"] = lbl @@ -30,9 +35,9 @@ end abstract type AbstractBayesTree end -const BTGdict = GenericIncidenceList{TreeClique,Edge{TreeClique},Array{TreeClique,1},Array{Array{Edge{TreeClique},1},1}} # BayesTree declarations +const BTGdict = GenericIncidenceList{TreeClique,Edge{TreeClique},Array{TreeClique,1},Array{Array{Edge{TreeClique},1},1}} """ $(TYPEDEF) @@ -79,10 +84,7 @@ Base.propertynames(x::MetaBayesTree, private::Bool=false) = (:bt, :btid, :clique Base.getproperty(x::MetaBayesTree,f::Symbol) = begin if f == :cliques - @warn "Moet die dalk nie gebruik nie" - # for (key,value) in x.bt.vprops - # - # end + @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" x.bt.vprops else getfield(x,f) @@ -95,9 +97,8 @@ function MetaBayesTree(tree::BayesTree) #deep copy over properties for v in tree.bt.vertices - set_prop!(mtree.bt, v.index, :label, deepcopy(v.attributes["label"])) - set_prop!(mtree.bt, v.index, :data, deepcopy(v.attributes["data"])) - set_prop!(mtree.bt, v.index, :attributes, Dict{String,Any}()) + # set_prop!(mtree.bt, v.index, :label, deepcopy(v.label)) + set_prop!(mtree.bt, v.index, :clique, deepcopy(v.data)) end ## TODO: placeholder for edge stored Channels @@ -111,8 +112,6 @@ function MetaBayesTree(tree::BayesTree) end -# abstract type AbstractBayesTreeNodeData end - """ $TYPEDEF @@ -139,7 +138,7 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem refactoring::Dict{Symbol, String} oldcliqdata::BTND logger::SimpleLogger - CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() # NOTE JT - GraphsDFG as default? + CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() CliqStateMachineContainer{BTND}(x1::G, x2::InMemoryDFGTypes, x3::BayesTree, diff --git a/test/runtests.jl b/test/runtests.jl index a866d4fad..ac1c6c8a1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,8 +24,7 @@ include("testPartialFactors.jl") include("testBayesTreeiSAM2Example.jl") end -#FIXME -# include("testTreeSaveLoad.jl") +include("testTreeSaveLoad.jl") @testset "Ensure converter types can be run from extending namespaces..." begin include("saveconvertertypes.jl") From b2dd38b52886f9118e4df54d496b580b96094f55 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Wed, 8 Jan 2020 17:19:37 +0200 Subject: [PATCH 22/57] MetaBayesTree wipeBuildNewTree! --- src/AdditionalUtils.jl | 2 +- src/CliqStateMachine.jl | 2 +- src/CliqStateMachineUtils.jl | 32 +++++++-------- src/InferDimensionUtils.jl | 2 +- src/JunctionTree.jl | 75 +++++++++++++++++++++++----------- src/JunctionTreeTypes.jl | 48 ++++++++++++---------- src/SolveTree01.jl | 14 +++---- src/SolverAPI.jl | 8 ++-- src/TreeBasedInitialization.jl | 24 +++++------ 9 files changed, 119 insertions(+), 88 deletions(-) diff --git a/src/AdditionalUtils.jl b/src/AdditionalUtils.jl index 02d4cb0ce..7d1a1a2aa 100644 --- a/src/AdditionalUtils.jl +++ b/src/AdditionalUtils.jl @@ -57,7 +57,7 @@ drawCliqSubgraphUpMocking, drawGraph, drawTree """ function drawGraphCliq(hists::Dict{Int, <: Tuple}, step::Int, - tree::BayesTree, + tree::AbstractBayesTree, frontal::Symbol; show::Bool=true ) # diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 783e77df0..31a42ce45 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -845,7 +845,7 @@ Notes: - Doesn't do partial initialized state properly yet. """ function cliqInitSolveUpByStateMachine!(dfg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::TreeClique; N::Int=100, oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index fe89d06dc..23a91d4f7 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -31,7 +31,7 @@ end Return dict of all histories in a Bayes Tree. """ function getTreeCliqsSolverHistories(fg::G, - tree::BayesTree)::Dict{Symbol, CSMHistory} where G <: AbstractDFG + tree::AbstractBayesTree)::Dict{Symbol, CSMHistory} where G <: AbstractDFG # fsy = getTreeAllFrontalSyms(fg, tree) histories = Dict{Symbol, CSMHistory}() @@ -56,7 +56,7 @@ Notes function getCliqSolveHistory(cliq::TreeClique) getData(cliq).statehistory end -function getCliqSolveHistory(tree::BayesTree, frntal::Symbol) +function getCliqSolveHistory(tree::AbstractBayesTree, frntal::Symbol) cliq = whichCliq(tree, frntal) getCliqSolveHistory(cliq) end @@ -113,7 +113,7 @@ function printCliqHistorySummary(hist::Vector{Tuple{DateTime, Int, Function, Cli printCliqHistorySummary(stdout, hist) end -function printCliqHistorySummary(hists::Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}, tree::BayesTree, sym::Symbol) +function printCliqHistorySummary(hists::Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}, tree::AbstractBayesTree, sym::Symbol) hist = hists[getCliq(tree, sym).index] printCliqHistorySummary(stdout, hist) end @@ -124,7 +124,7 @@ function printCliqHistorySummary(cliq::TreeClique) printCliqHistorySummary(hist) end -function printCliqHistorySummary(tree::BayesTree, frontal::Symbol) +function printCliqHistorySummary(tree::AbstractBayesTree, frontal::Symbol) hist = getCliqSolveHistory(tree, frontal) printCliqHistorySummary(hist) end @@ -137,7 +137,7 @@ Repeat a solver state machine step without changing history or primary values. printCliqSummary, printCliqHistorySummary, getCliqSolveHistory, cliqHistFilterTransitions """ -function sandboxCliqResolveStep(tree::BayesTree, +function sandboxCliqResolveStep(tree::AbstractBayesTree, frontal::Symbol, step::Int) # @@ -166,7 +166,7 @@ Related printCliqHistorySummary """ -function animateCliqStateMachines(tree::BayesTree, +function animateCliqStateMachines(tree::AbstractBayesTree, cliqsyms::Vector{Symbol}; frames::Int=100 ) # @@ -228,7 +228,7 @@ Related: getCliqSolveHistory, printCliqHistorySummary, cliqHistFilterTransitions, sandboxCliqResolveStep """ -function filterHistAllToArray(tree::BayesTree, frontals::Vector{Symbol}, nextfnc::Function) +function filterHistAllToArray(tree::AbstractBayesTree, frontals::Vector{Symbol}, nextfnc::Function) ret = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}() for sym in frontals hist = getCliqSolveHistory(tree, sym) @@ -250,7 +250,7 @@ Related: initInferTreeUp! """ function solveCliqWithStateMachine!(dfg::G, - tree::BayesTree, + tree::AbstractBayesTree, frontal::Symbol; iters::Int=200, downsolve::Bool=true, @@ -313,7 +313,7 @@ run(`vlc /tmp/caesar/csmCompound/out.mp4`) ``` """ function csmAnimate(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqsyms::Vector{Symbol}; frames::Int=100, rmfirst::Bool=true ) where G <: AbstractDFG @@ -362,7 +362,7 @@ Related csmAnimate, printCliqHistorySummary """ function makeCsmMovie(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqs=ls(fg); assignhist=nothing, show::Bool=true, @@ -397,7 +397,7 @@ Dev Notes - Very closely related to getCliqSiblingsPartialNeeds -- refactor likely (NOTE). - should precompute `allinters`. """ -function getSiblingsDelayOrder(tree::BayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getSiblingsDelayOrder(tree::AbstractBayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # when is a cliq upsolved solvedstats = Symbol[:upsolved; :marginalized; :uprecycled] @@ -546,7 +546,7 @@ Determine clique truely isn't able to proceed any further: - change status to :mustinitdown if have only partial beliefs so far: - combination of status, while partials belief siblings are not :mustinitdown """ -function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getCliqSiblingsPartialNeeds(tree::AbstractBayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # which incoming messages are partials hasPartials = Dict{Symbol, Int}() for (sym, tmsg) in dwinmsgs @@ -597,7 +597,7 @@ end Bump a clique state machine solver condition in case a task might be waiting on it. """ -notifyCSMCondition(tree::BayesTree, frsym::Symbol) = notify(getSolveCondition(whichCliq(tree, frsym))) +notifyCSMCondition(tree::AbstractBayesTree, frsym::Symbol) = notify(getSolveCondition(whichCliq(tree, frsym))) """ @@ -647,7 +647,7 @@ Notes - Relies on sibling priority order with only one "currently best" option that will force progress in global upward inference. - Return false if one of the siblings is still busy """ -function areSiblingsRemaingNeedDownOnly(tree::BayesTree, +function areSiblingsRemaingNeedDownOnly(tree::AbstractBayesTree, cliq::TreeClique )::Bool # stillbusylist = [:null; :initialized;] @@ -724,11 +724,11 @@ Related getGraphFromHistory, printCliqHistorySummary, printCliqSummary """ getCliqSubgraphFromHistory(hist::Vector{<:Tuple}, step::Int) = hist[step][4].cliqSubFg -getCliqSubgraphFromHistory(tree::BayesTree, frnt::Symbol, step::Int) = getCliqSubgraphFromHistory(getCliqSolveHistory(tree, frnt), step) +getCliqSubgraphFromHistory(tree::AbstractBayesTree, frnt::Symbol, step::Int) = getCliqSubgraphFromHistory(getCliqSolveHistory(tree, frnt), step) function printCliqSummary(dfg::G, - tree::BayesTree, + tree::AbstractBayesTree, frs::Symbol, logger=ConsoleLogger() ) where G <: AbstractDFG # diff --git a/src/InferDimensionUtils.jl b/src/InferDimensionUtils.jl index ae3766262..e0323bd5c 100644 --- a/src/InferDimensionUtils.jl +++ b/src/InferDimensionUtils.jl @@ -375,7 +375,7 @@ Related fetchCliqSolvableDims, getCliqVariableMoreInitDims, getSubFgPriorityInitOrder """ -function getCliqSiblingsPriorityInitOrder(tree::BayesTree, +function getCliqSiblingsPriorityInitOrder(tree::AbstractBayesTree, prnt::TreeClique, logger=ConsoleLogger() )::Vector{Int} # diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 14e7e2446..bbd1560ea 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -21,10 +21,18 @@ getFrontals(cliqd::Union{TreeClique,BayesTreeNodeData})::Vector{Symbol} = getCli Create a new clique. """ -function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::TreeClique where G <: AbstractDFG +function addClique!(bt::AbstractBayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::TreeClique where G <: AbstractDFG bt.btid += 1 - clq = Graphs.add_vertex!(bt.bt, TreeClique(bt.btid,string("Clique",bt.btid))) - bt.cliques[bt.btid] = clq + + if isa(bt.bt,GenericIncidenceList) + clq = Graphs.add_vertex!(bt.bt, TreeClique(bt.btid,string("Clique",bt.btid))) + bt.cliques[bt.btid] = clq + elseif isa(bt.bt, MetaDiGraph) + clq = TreeClique(bt.btid, string("Clique", bt.btid)) + MetaGraphs.add_vertex!(bt.bt, :clique, clq) + else + error("Oops, something went wrong") + end setLabel!(clq, "") @@ -35,12 +43,13 @@ function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol} return clq end + """ $SIGNATURES Generate the label for particular clique (used by graphviz for visualization). """ -function makeCliqueLabel(dfg::G, bt::BayesTree, clqID::Int)::String where G <: AbstractDFG +function makeCliqueLabel(dfg::G, bt::AbstractBayesTree, clqID::Int)::String where G <: AbstractDFG clq = bt.cliques[clqID] flbl = "" clbl = "" @@ -58,7 +67,7 @@ end Add the separator for the newly created clique. """ -function appendSeparatorToClique(bt::BayesTree, clqID::Int, seprIDs::Array{Symbol,1}) +function appendSeparatorToClique(bt::AbstractBayesTree, clqID::Int, seprIDs::Array{Symbol,1}) union!(getData(bt.cliques[clqID]).separatorIDs, seprIDs) nothing end @@ -71,13 +80,13 @@ Add a new frontal variable to clique. DevNotes - TODO, define what "conditionals" are CLEARLY!! """ -function appendClique!(bt::BayesTree, +function appendClique!(bt::AbstractBayesTree, clqID::Int, dfg::AbstractDFG, varID::Symbol, seprIDs::Array{Symbol,1}=Symbol[] )::Nothing # - clq = bt.cliques[clqID] + clq = bt.cliques[clqID] #TODO replace with getClique var = DFG.getVariable(dfg, varID) # add frontal variable @@ -98,13 +107,22 @@ end Instantiate a new child clique in the tree. """ -function newChildClique!(bt::BayesTree, dfg::AbstractDFG, CpID::Int, varID::Symbol, Sepj::Array{Symbol,1}) +function newChildClique!(bt::AbstractBayesTree, dfg::AbstractDFG, CpID::Int, varID::Symbol, Sepj::Array{Symbol,1}) # physically create the new clique chclq = addClique!(bt, dfg, varID, Sepj) parent = bt.cliques[CpID] - # Staying with Graphs.jl for tree in first stage - edge = Graphs.make_edge(bt.bt, parent, chclq) - Graphs.add_edge!(bt.bt, edge) + + if isa(bt.bt,GenericIncidenceList) + # Staying with Graphs.jl for tree in first stage + edge = Graphs.make_edge(bt.bt, parent, chclq) + Graphs.add_edge!(bt.bt, edge) + elseif isa(bt.bt, MetaDiGraph) + # TODO EDGE properties here + MetaGraphs.add_edge!(bt.bt, parent.index, chclq.index) + else + error("Oops, something went wrong") + end + return chclq end @@ -163,7 +181,7 @@ Kaess et al.: Bayes Tree, WAFR, 2010, [Alg. 2] Kaess et al.: iSAM2, IJRR, 2011, [Alg. 3] Fourie, D.: mmisam, PhD thesis, 2017. [Chpt. 5] """ -function newPotential(tree::BayesTree, dfg::G, var::Symbol, elimorder::Array{Symbol,1}) where G <: AbstractDFG +function newPotential(tree::AbstractBayesTree, dfg::G, var::Symbol, elimorder::Array{Symbol,1}) where G <: AbstractDFG firvert = DFG.getVariable(dfg,var) # no parent if (length(solverData(firvert).separator) == 0) @@ -204,7 +222,7 @@ end Build the whole tree in batch format. """ -function buildTree!(tree::BayesTree, dfg::AbstractDFG, elimorder::Array{Symbol,1}) +function buildTree!(tree::AbstractBayesTree, dfg::AbstractDFG, elimorder::Array{Symbol,1}) revorder = reverse(elimorder,dims=1) # flipdim(p, 1), fixing #499 # prevVar = 0 for var in revorder @@ -543,7 +561,7 @@ function wipeBuildNewTree!(dfg::G; viewerapp::String="evince", imgs::Bool=false, maxparallel::Int=50, - variableOrder::Union{Nothing, Vector{Symbol}}=nothing )::BayesTree where G <: AbstractDFG + variableOrder::Union{Nothing, Vector{Symbol}}=nothing )::AbstractBayesTree where G <: AbstractDFG # resetFactorGraphNewTree!(dfg); return prepBatchTree!(dfg, variableOrder=variableOrder, ordering=ordering, drawpdf=drawpdf, show=show, filepath=filepath, viewerapp=viewerapp, imgs=imgs, maxparallel=maxparallel); @@ -604,7 +622,7 @@ function getCliqDepth(tree, cliq)::Int end return getCliqDepth(tree, prnt[1]) + 1 end -getCliqDepth(tree::BayesTree, sym::Symbol)::Int = getCliqDepth(tree, getCliq(tree, sym)) +getCliqDepth(tree::AbstractBayesTree, sym::Symbol)::Int = getCliqDepth(tree, getCliq(tree, sym)) @@ -801,7 +819,7 @@ end Determine and set the potentials for a particular `cliq` in the Bayes (Junction) tree. """ function setCliqPotentials!(dfg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliq::TreeClique; solvable::Int=1 ) where G <: AbstractDFG # @@ -851,9 +869,9 @@ end Collect and returl all child clique separator variables. """ -function collectSeparators(bt::BayesTree, cliq::TreeClique)::Vector{Symbol} +function collectSeparators(bt::AbstractBayesTree, cliq::TreeClique)::Vector{Symbol} allseps = Symbol[] - for child in out_neighbors(cliq, bt.bt)#tree + for child in childCliqs(bt, cliq)#tree allseps = [allseps; getData(child).separatorIDs] end return allseps @@ -1095,7 +1113,7 @@ end Get each clique subgraph association matrix. """ -function compCliqAssocMatrices!(dfg::G, bt::BayesTree, cliq::TreeClique) where G <: AbstractDFG +function compCliqAssocMatrices!(dfg::G, bt::AbstractBayesTree, cliq::TreeClique) where G <: AbstractDFG frtl = getCliqFrontalVarIds(cliq) cond = getCliqSeparatorVarIds(cliq) inmsgIDs = collectSeparators(bt, cliq) @@ -1313,8 +1331,8 @@ end # post order tree traversal and build potential functions -function buildCliquePotentials(dfg::G, bt::BayesTree, cliq::TreeClique; solvable::Int=1) where G <: AbstractDFG - for child in out_neighbors(cliq, bt.bt)#tree +function buildCliquePotentials(dfg::G, bt::AbstractBayesTree, cliq::TreeClique; solvable::Int=1) where G <: AbstractDFG + for child in childCliqs(bt, cliq)#tree buildCliquePotentials(dfg, bt, child) end @info "Get potentials $(getLabel(cliq))" @@ -1342,6 +1360,15 @@ function childCliqs(treel::BayesTree, frtsym::Symbol) childCliqs(treel, whichCliq(treel, frtsym)) end + +function childCliqs(treel::MetaBayesTree, cliq::TreeClique) + childcliqs = TreeClique[] + for cIdx in MetaGraphs.outneighbors(treel.bt, cliq.index) + push!(childcliqs, get_prop(treel.bt, cIdx, :clique)) + end + return childcliqs +end + """ $(SIGNATURES) @@ -1403,7 +1430,7 @@ Related: whichCliq, printCliqHistorySummary """ -function getTreeAllFrontalSyms(fgl::G, tree::BayesTree) where G <: AbstractDFG +function getTreeAllFrontalSyms(fgl::G, tree::AbstractBayesTree) where G <: AbstractDFG cliqs = tree.cliques syms = Vector{Symbol}(undef, length(cliqs)) for (id,cliq) in cliqs @@ -1430,7 +1457,7 @@ Related getUpMsgs """ -function getTreeCliqUpMsgsAll(tree::BayesTree)::Dict{Int,TempBeliefMsg} +function getTreeCliqUpMsgsAll(tree::AbstractBayesTree)::Dict{Int,TempBeliefMsg} allUpMsgs = Dict{Int,TempBeliefMsg}() for (idx,cliq) in tree.cliques msgs = getUpMsgs(cliq) @@ -1458,7 +1485,7 @@ Notes inferredDim -- Information count } """ -function stackCliqUpMsgsByVariable(tree::BayesTree, +function stackCliqUpMsgsByVariable(tree::AbstractBayesTree, tmpmsgs::Dict{Int, TempBeliefMsg} )::TempUpMsgPlotting # # start of the return data structure diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index ccfbb1951..5baac0fef 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -62,7 +62,7 @@ function emptyBayesTree() 0.0 ) return bt end - +# emptyBayesTree() = MetaBayesTree() # TODO DEV MetaGraphs bayes tree, will potentially also make a LightBayesTree, CloudBayesTree, """ @@ -85,7 +85,11 @@ Base.propertynames(x::MetaBayesTree, private::Bool=false) = (:bt, :btid, :clique Base.getproperty(x::MetaBayesTree,f::Symbol) = begin if f == :cliques @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" - x.bt.vprops + d = Dict{Int,Any}() + for (k,v) in x.bt.vprops + d[k] = v[:clique] + end + return d else getfield(x,f) end @@ -98,7 +102,7 @@ function MetaBayesTree(tree::BayesTree) #deep copy over properties for v in tree.bt.vertices # set_prop!(mtree.bt, v.index, :label, deepcopy(v.label)) - set_prop!(mtree.bt, v.index, :clique, deepcopy(v.data)) + set_prop!(mtree.bt, v.index, :clique, deepcopy(v)) end ## TODO: placeholder for edge stored Channels @@ -122,10 +126,10 @@ TODO - remove proceed - more direct clique access (cliq, parent, children), for multi-process solves """ -mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMemoryDFGTypes} +mutable struct CliqStateMachineContainer{BTND, BT <: AbstractBayesTree, T <: AbstractDFG, InMemG <: InMemoryDFGTypes} dfg::T cliqSubFg::InMemG - tree::BayesTree + tree::BT cliq::TreeClique parentCliq::Vector{TreeClique} childCliqs::Vector{TreeClique} @@ -138,27 +142,27 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem refactoring::Dict{Symbol, String} oldcliqdata::BTND logger::SimpleLogger - CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() - CliqStateMachineContainer{BTND}(x1::G, - x2::InMemoryDFGTypes, - x3::BayesTree, - x4::TreeClique, - x5::Vector{TreeClique}, - x6::Vector{TreeClique}, - x7::Bool, - x8::Bool, - x9::Bool, - x10a::Bool, - x10aa::Bool, - x10aaa::SolverParams, - x10b::Dict{Symbol,String}=Dict{Symbol,String}(), - x11::BTND=emptyBTNodeData(), - x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} = new{BTND, G, typeof(x2)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10a,x10aa,x10aaa,x10b,x11, x13) + # CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() + # CliqStateMachineContainer{BTND}(x1::G, + # x2::InMemoryDFGTypes, + # x3::BayesTree, + # x4::TreeClique, + # x5::Vector{TreeClique}, + # x6::Vector{TreeClique}, + # x7::Bool, + # x8::Bool, + # x9::Bool, + # x10a::Bool, + # x10aa::Bool, + # x10aaa::SolverParams, + # x10b::Dict{Symbol,String}=Dict{Symbol,String}(), + # x11::BTND=emptyBTNodeData(), + # x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} = new{BTND, G, typeof(x2)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10a,x10aa,x10aaa,x10b,x11, x13) end function CliqStateMachineContainer(x1::G, x2::InMemoryDFGTypes, - x3::BayesTree, + x3::AbstractBayesTree, x4::TreeClique, x5::Vector{TreeClique}, x6::Vector{TreeClique}, diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index bc20d6e7a..fdb677aa8 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -575,7 +575,7 @@ Calculate a fresh (single step) approximation to the variable `sym` in clique `c Which clique to be used is defined by frontal variable symbols (`cliq` in this case) -- see `whichCliq(...)` for more details. The `sym` symbol indicates which symbol of this clique to be calculated. **Note** that the `sym` variable must appear in the clique where `cliq` is a frontal variable. """ function treeProductUp(fg::AbstractDFG, - tree::BayesTree, + tree::AbstractBayesTree, cliq::Symbol, sym::Symbol; N::Int=100, @@ -617,7 +617,7 @@ Calculate a fresh---single step---approximation to the variable `sym` in clique Which clique to be used is defined by frontal variable symbols (`cliq` in this case) -- see `whichCliq(...)` for more details. The `sym` symbol indicates which symbol of this clique to be calculated. **Note** that the `sym` variable must appear in the clique where `cliq` is a frontal variable. """ function treeProductDwn(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::Symbol, sym::Symbol; N::Int=100, @@ -1248,7 +1248,7 @@ Run through entire tree and set cliques as marginalized if all clique variables Notes: - TODO can be made fully parallel, consider converting for use with `@threads` `for`. """ -function updateTreeCliquesAsMarginalizedFromVars!(fgl::FactorGraph, tree::BayesTree)::Nothing +function updateTreeCliquesAsMarginalizedFromVars!(fgl::FactorGraph, tree::AbstractBayesTree)::Nothing for (clid, cliq) in tree.cliques if isCliqMarginalizedFromVars(fgl, cliq) setCliqAsMarginalized!(cliq, true) @@ -1286,7 +1286,7 @@ based on contents of `seeksSimilar::BayesTreeNodeData`. Notes - Used to identify and skip similar cliques (i.e. recycle computations) """ -function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeNodeData)::TreeClique +function attemptTreeSimilarClique(othertree::AbstractBayesTree, seeksSimilar::BayesTreeNodeData)::TreeClique # inner convenience function for returning empty clique function EMPTYCLIQ() clq = TreeClique(-1,"null") @@ -1435,7 +1435,7 @@ function fetchCliqTaskHistoryAll!(smt, hist) end end -function fetchAssignTaskHistoryAll!(tree::BayesTree, smt) +function fetchAssignTaskHistoryAll!(tree::AbstractBayesTree, smt) hist = Dict{Int, Vector{Tuple{DateTime,Int,Function,CliqStateMachineContainer}}}() fetchCliqTaskHistoryAll!(smt, hist) assignTreeHistory!(tree, hist) @@ -1457,7 +1457,7 @@ initInferTreeUp! """ function asyncTreeInferUp!(dfg::G, treel::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, limititers::Int=-1, @@ -1514,7 +1514,7 @@ asyncTreeInferUp! """ function initInferTreeUp!(dfg::G, treel::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, limititers::Int=-1, diff --git a/src/SolverAPI.jl b/src/SolverAPI.jl index 012509169..2b0123729 100644 --- a/src/SolverAPI.jl +++ b/src/SolverAPI.jl @@ -21,7 +21,7 @@ Related solveCliq!, wipeBuildNewTree! """ function solveTree!(dfgl::G, - oldtree::BayesTree=emptyBayesTree(); + oldtree::AbstractBayesTree=emptyBayesTree(); delaycliqs::Vector{Symbol}=Symbol[], recordcliqs::Vector{Symbol}=Symbol[], skipcliqids::Vector{Symbol}=Symbol[], @@ -78,7 +78,7 @@ Related solveTree!, wipeBuildNewTree! """ function solveCliq!(dfgl::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqid::Symbol; recordcliq::Bool=false, # cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}(), @@ -117,7 +117,7 @@ Notes """ function inferOverTree!(dfg::G, bt::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + oldtree::AbstractBayesTree=emptyBayesTree(), N::Int=100, upsolve::Bool=true, downsolve::Bool=true, @@ -212,7 +212,7 @@ end Perform multimodal incremental smoothing and mapping (mm-iSAM) computations over given factor graph `fgl::FactorGraph` on the local computer. A pdf of the Bayes (Junction) tree will be generated in the working folder with `drawpdf=true` """ function batchSolve!(dfg::G, - oldtree::BayesTree=emptyBayesTree(); + oldtree::AbstractBayesTree=emptyBayesTree(); upsolve::Bool=true, downsolve::Bool=true, drawpdf::Bool=false, diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index 40b78731d..e7eac2a1d 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -208,7 +208,7 @@ end Determine if this `cliq` has been fully initialized and child cliques have completed their full upward inference. """ -function isCliqReadyInferenceUp(fgl::FactorGraph, tree::BayesTree, cliq::TreeClique) +function isCliqReadyInferenceUp(fgl::FactorGraph, tree::AbstractBayesTree, cliq::TreeClique) isallinit = areCliqVariablesAllInitialized(fgl, cliq) # check that all child cliques have also completed full up inference. @@ -284,7 +284,7 @@ end Set all Bayes (Junction) tree cliques that have all marginalized and initialized variables. """ function setTreeCliquesMarginalized!(dfg::G, - tree::BayesTree) where G <: AbstractDFG + tree::AbstractBayesTree) where G <: AbstractDFG # for (cliid, cliq) in tree.cliques if areCliqVariablesAllMarginalized(dfg, cliq) @@ -344,7 +344,7 @@ Notes: - See status options at `getCliqStatusUp(..)`. - Can be called multiple times """ -function blockCliqUntilChildrenHaveUpStatus(tree::BayesTree, +function blockCliqUntilChildrenHaveUpStatus(tree::AbstractBayesTree, prnt::TreeClique, logger=ConsoleLogger() )::Dict{Int, Symbol} # @@ -375,7 +375,7 @@ Notes - used for regulating long need down message chains. - exit strategy is parent becomes status `:initialized`. """ -function blockCliqSiblingsParentNeedDown(tree::BayesTree, +function blockCliqSiblingsParentNeedDown(tree::AbstractBayesTree, cliq::TreeClique; logger=ConsoleLogger()) # with_logger(logger) do @@ -474,7 +474,7 @@ end Update `subfg<:AbstractDFG` according to internal computations for a full upsolve. """ function doCliqUpSolve!(subfg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::TreeClique; multiproc::Bool=true, logger=ConsoleLogger() )::Symbol where G <: AbstractDFG @@ -510,7 +510,7 @@ function prepCliqInitMsgsUp(subfg::G, return msg end -function prepCliqInitMsgsUp(subfg::G, tree::BayesTree, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG +function prepCliqInitMsgsUp(subfg::G, tree::AbstractBayesTree, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG @warn "deprecated, use prepCliqInitMsgsUp(subfg::FactorGraph, cliq::TreeClique) instead" prepCliqInitMsgsUp(subfg, cliq) end @@ -528,7 +528,7 @@ Notes - must use factors in cliq only, ensured by using subgraph -- TODO general case. """ function doCliqAutoInitUpPart1!(subfg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::TreeClique; up_solve_if_able::Bool=true, multiproc::Bool=true, @@ -571,7 +571,7 @@ Notes - must use factors in cliq only, ensured by using subgraph -- TODO general case. """ function doCliqAutoInitUpPart2!(subfg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::TreeClique; # msgfcts; up_solve_if_able::Bool=true, @@ -765,7 +765,7 @@ Dev Notes - This should be the initialization cycle of parent, build up bit by bit... """ function prepCliqInitMsgsDown!(fgl::G, - tree::BayesTree, + tree::AbstractBayesTree, prnt::TreeClique, cliq::TreeClique; logger=ConsoleLogger(), @@ -1080,7 +1080,7 @@ function doCliqInitDown!(subfg::G, end function doCliqInitDown!(subfg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::TreeClique; dbg::Bool=false ) where G <: AbstractDFG # @@ -1107,7 +1107,7 @@ function areCliqChildrenNeedDownMsg(children::Vector{TreeClique})::Bool return false end -function areCliqChildrenNeedDownMsg(tree::BayesTree, cliq::TreeClique)::Bool +function areCliqChildrenNeedDownMsg(tree::AbstractBayesTree, cliq::TreeClique)::Bool areCliqChildrenNeedDownMsg( getChildren(tree, cliq) ) end @@ -1117,7 +1117,7 @@ end Return true if has parent with status `:needdownmsg`. """ -function isCliqParentNeedDownMsg(tree::BayesTree, cliq::TreeClique, logger=ConsoleLogger()) +function isCliqParentNeedDownMsg(tree::AbstractBayesTree, cliq::TreeClique, logger=ConsoleLogger()) prnt = getParent(tree, cliq) if length(prnt) == 0 return false From 4d6f3e4c7b19bc571308fa3cc9d7b91515939a6b Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 9 Jan 2020 11:43:06 +0200 Subject: [PATCH 23/57] MetaBayesTree solves --- src/AdditionalUtils.jl | 2 +- src/CliqStateMachine.jl | 10 +++--- src/CliqStateMachineUtils.jl | 12 +++---- src/Deprecated.jl | 24 ++++++------- src/IncrementalInference.jl | 3 +- src/JunctionTree.jl | 57 ++++++++++++++++++++----------- src/JunctionTreeTypes.jl | 45 ++++++++++++++++-------- src/SolveTree01.jl | 38 ++++++++++----------- src/SolverAPI.jl | 8 ++--- src/SolverUtilities.jl | 4 +-- src/SubGraphFunctions.jl | 2 +- src/TreeBasedInitialization.jl | 2 +- test/runtests.jl | 1 + test/testBayesTreeiSAM2Example.jl | 2 +- 14 files changed, 121 insertions(+), 89 deletions(-) diff --git a/src/AdditionalUtils.jl b/src/AdditionalUtils.jl index 7d1a1a2aa..54b8b233a 100644 --- a/src/AdditionalUtils.jl +++ b/src/AdditionalUtils.jl @@ -14,7 +14,7 @@ Related drawGraphCliq, spyCliqMat, drawTree, buildCliqSubgraphUp, buildSubgraphFromLabels! """ function drawCliqSubgraphUpMocking(fgl::G, - treel::BayesTree, + treel::AbstractBayesTree, frontalSym::Symbol; show::Bool=true, filepath::String="/tmp/cliq_sfg.pdf", diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 31a42ce45..3c07c156d 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -848,7 +848,7 @@ function cliqInitSolveUpByStateMachine!(dfg::G, tree::AbstractBayesTree, cliq::TreeClique; N::Int=100, - oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), + oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), drawtree::Bool=false, show::Bool=false, incremental::Bool=true, @@ -859,16 +859,14 @@ function cliqInitSolveUpByStateMachine!(dfg::G, delay::Bool=false, logger::SimpleLogger=SimpleLogger(Base.stdout)) where {G <: AbstractDFG, AL <: AbstractLogger} # - children = TreeClique[] - for ch in Graphs.out_neighbors(cliq, tree.bt) - push!(children, ch) - end + children = getChildren(tree, cliq)#Graphs.out_neighbors(cliq, tree.bt) + prnt = getParent(tree, cliq) destType = (G <: InMemoryDFGTypes) ? G : InMemDFGType#GraphsDFG{SolverParams} #csmc = CliqStateMachineContainer(dfg, initfg(destType), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), oldcliqdata, logger) - csmc = CliqStateMachineContainer(dfg, initfg(destType, params=getSolverParams(dfg)), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), oldcliqdata, logger) + csmc = CliqStateMachineContainer(dfg, initfg(destType, params=getSolverParams(dfg)), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), Dict{Symbol,String}(), oldcliqdata, logger) nxt = upsolve ? testCliqCanRecycled_StateMachine : (downsolve ? testCliqCanRecycled_StateMachine : error("must attempt either up or down solve")) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index 23a91d4f7..2b8868a57 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -1,4 +1,3 @@ - """ $SIGNATURES @@ -260,10 +259,9 @@ function solveCliqWithStateMachine!(dfg::G, prevcsmc::Union{Nothing,CliqStateMachineContainer}=nothing) where G <: AbstractDFG # cliq = whichCliq(tree, frontal) - children = TreeClique[] - for ch in Graphs.out_neighbors(cliq, tree.bt) - push!(children, ch) - end + + children = getChildren(tree, cliq)#Graphs.out_neighbors(cliq, tree.bt) + prnt = getParent(tree, cliq) destType = (G <: InMemoryDFGTypes) ? G : InMemDFGType#GraphsDFG{SolverParams} @@ -1009,7 +1007,7 @@ DevNotes - TODO review, are all updates atomic?? Then perhaps in-memory only can be reduced to references back to csmc.dfg. """ function buildCliqSubgraph(dfg::AbstractDFG, - treel::BayesTree, + treel::AbstractBayesTree, cliq::TreeClique, subfg::InMemoryDFGTypes=InMemDFGType(params=getSolverParams(dfg)) ) # @@ -1039,7 +1037,7 @@ end # addMsgFactors!(subfg, msgs) function buildCliqSubgraph(fgl::AbstractDFG, - treel::BayesTree, + treel::AbstractBayesTree, cliqsym::Symbol, subfg::InMemDFGType=InMemDFGType(params=getSolverParams(fgl)) ) # diff --git a/src/Deprecated.jl b/src/Deprecated.jl index 6848f7c08..9b5f9768c 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -267,7 +267,7 @@ function upMsg(cliq::TreeClique) @warn "deprecated upMsg, use getUpMsg instead" getData(cliq).upMsg end -function upMsg(btl::BayesTree, sym::Symbol) +function upMsg(btl::AbstractBayesTree, sym::Symbol) @warn "deprecated upMsg, use getUpMsg instead" upMsg(whichCliq(btl, sym)) end @@ -281,13 +281,13 @@ function dwnMsg(cliq::TreeClique) @warn "deprecated dwnMsg, use getDwnMsgs instead" getData(cliq).dwnMsg end -function dwnMsg(btl::BayesTree, sym::Symbol) +function dwnMsg(btl::AbstractBayesTree, sym::Symbol) @warn "deprecated dwnMsg, use getDwnMsgs instead" dwnMsg(whichCliq(btl, sym)) end -function getCliquePotentials!(fg::FactorGraph, bt::BayesTree, chkcliq::Int) +function getCliquePotentials!(fg::FactorGraph, bt::AbstractBayesTree, chkcliq::Int) @error "getCliquePotentials! deprecated, use setCliqPotentials! with DFG objects instead of FactorGraph" setCliqPotentials!(fg, bt.cliques[chkcliq]) end @@ -358,7 +358,7 @@ function downGibbsCliqueDensity(inp::ExploreTreeType{T}, return downGibbsCliqueDensity(inp.fg, inp.cliq, inp.sendmsgs, N, mcmciter, dbg) end -function prepDwnPreOrderStack!(bt::BayesTree, +function prepDwnPreOrderStack!(bt::AbstractBayesTree, parentStack::Array{TreeClique,1}) # dwn message passing function nodedata = nothing @@ -392,7 +392,7 @@ function findVertsAssocCliq(fgl::FactorGraph, cliq::TreeClique) nothing end -function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::TreeClique, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG +function partialExploreTreeType(pfg::G, pbt::AbstractBayesTree, cliqCursor::TreeClique, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG # info("starting pett") # TODO -- expand this to grab only partial subsection from the fg and bt data structures @@ -406,7 +406,7 @@ function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::TreeClique, end function dispatchNewDwnProc!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, parentStack::Array{TreeClique,1}, stkcnt::Int, refdict::Dict{Int,Future}; @@ -447,7 +447,7 @@ Notes - Simultaenously launches as many async dispatches to remote processes as there are cliques in the tree. """ function processPreOrderStack!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, parentStack::Array{TreeClique,1}, refdict::Dict{Int,Future}; N::Int=100, @@ -495,7 +495,7 @@ function downMsgPassingIterative!(startett::ExploreTreeType{T}; nothing end -function prepPostOrderUpPassStacks!(bt::BayesTree, +function prepPostOrderUpPassStacks!(bt::AbstractBayesTree, parentStack::Array{TreeClique,1}, childStack::Array{TreeClique,1} ) # upward message passing preparation @@ -522,7 +522,7 @@ end Asynchronously perform up message passing, based on previoulsy prepared `chldstk::Vector{TreeClique}`. """ function asyncProcessPostStacks!(fgl::G, - bt::BayesTree, + bt::AbstractBayesTree, chldstk::Vector{TreeClique}, stkcnt::Int, refdict::Dict{Int,Future}; @@ -595,7 +595,7 @@ Notes - separate multithreaded calls can occur on each separate process. """ function processPostOrderStacks!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, childStack::Array{TreeClique,1}; N::Int=100, dbg::Bool=false, @@ -633,7 +633,7 @@ end Return clique pointers for the given order in which they will be solved (sequentially). """ -function getCliqOrderUpSolve(treel::BayesTree, startcliq=treel.cliques[1]) +function getCliqOrderUpSolve(treel::AbstractBayesTree, startcliq=treel.cliques[1]) # http://www.geeksforgeeks.org/iterative-postorder-traversal/ # this is where we launch the downward iteration process from parentStack = Vector{TreeClique}() @@ -650,7 +650,7 @@ end Return clique pointers for the given order in which they will be solved (sequentially). """ -getTreeCliqSolveOrderUp(treel::BayesTree, startcliq=treel.cliques[1]) = getCliqOrderUpSolve(treel, startcliq) +getTreeCliqSolveOrderUp(treel::AbstractBayesTree, startcliq=treel.cliques[1]) = getCliqOrderUpSolve(treel, startcliq) """ $SIGNATURES diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index dc904dcb7..38c84f514 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -294,6 +294,7 @@ export parentCliq, getParent, getCliqSiblings, + getNumCliqs, getKDE, getVertKDE, initializeNode!, @@ -596,7 +597,7 @@ function __init__() push!(sp.guides, Gadfly.Guide.ylabel("lcl=$(numlcl) || msg=$(size(getCliqMsgMat(cliq),1))" )) return sp end - function spyCliqMat(bt::BayesTree, lbl::Symbol; showmsg=true, suppressprint::Bool=false) + function spyCliqMat(bt::AbstractBayesTree, lbl::Symbol; showmsg=true, suppressprint::Bool=false) spyCliqMat(whichCliq(bt,lbl), showmsg=showmsg, suppressprint=suppressprint) end end diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index bbd1560ea..9182294c0 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -132,7 +132,7 @@ end Post order tree traversal and build potential functions """ -function findCliqueFromFrontal(bt::BayesTree, frtlID::Int) +function findCliqueFromFrontal(bt::AbstractBayesTree, frtlID::Int) for cliqPair in bt.cliques id = cliqPair[1] cliq = cliqPair[2] @@ -313,7 +313,7 @@ Related: drawTree """ -function generateTexTree(treel::BayesTree; +function generateTexTree(treel::AbstractBayesTree; filepath::String="/tmp/caesar/bayes/bt") btc = deepcopy(treel) for (cid, cliq) in btc.cliques @@ -538,7 +538,7 @@ end Reset factor graph and build a new tree from the provided variable ordering `p`. """ -function resetBuildTreeFromOrder!(fgl::AbstractDFG, p::Vector{Symbol})::BayesTree +function resetBuildTreeFromOrder!(fgl::AbstractDFG, p::Vector{Symbol})::AbstractBayesTree resetFactorGraphNewTree!(fgl) return buildTreeFromOrdering!(fgl, p) end @@ -580,7 +580,7 @@ Related: getCliq, getTreeAllFrontalSyms """ -getCliq(bt::BayesTree, frt::Symbol) = bt.cliques[bt.frontals[frt]] +getCliq(bt::AbstractBayesTree, frt::Symbol) = bt.cliques[bt.frontals[frt]] """ $(SIGNATURES) @@ -595,8 +595,8 @@ Related: getCliq, getTreeAllFrontalSyms """ -whichCliq(bt::BayesTree, frt::Symbol) = getCliq(bt, frt) -whichCliq(bt::BayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Symbol(string(frt))) +whichCliq(bt::AbstractBayesTree, frt::Symbol) = getCliq(bt, frt) +whichCliq(bt::AbstractBayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Symbol(string(frt))) """ @@ -604,7 +604,7 @@ whichCliq(bt::BayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Sym Return boolean on whether the frontal variable `frt::Symbol` exists somewhere in the `::BayesTree`. """ -hasCliq(bt::BayesTree, frt::Symbol)::Bool = haskey(bt.frontals, frt) +hasCliq(bt::AbstractBayesTree, frt::Symbol)::Bool = haskey(bt.frontals, frt) """ $SIGNATURES @@ -654,7 +654,7 @@ end Return the last up message stored in `cliq` of Bayes (Junction) tree. """ getUpMsgs(cliql::TreeClique) = getData(cliql).upMsg -getUpMsgs(btl::BayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) +getUpMsgs(btl::AbstractBayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) """ $(SIGNATURES) @@ -662,7 +662,7 @@ getUpMsgs(btl::BayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) Return the last up message stored in `cliq` of Bayes (Junction) tree. """ getCliqMsgsUp(cliql::TreeClique) = upMsg(cliql) -getCliqMsgsUp(treel::BayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt)) +getCliqMsgsUp(treel::AbstractBayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt)) """ $(SIGNATURES) @@ -679,7 +679,7 @@ end Return the last down message stored in `cliq` of Bayes (Junction) tree. """ getDwnMsgs(cliql::TreeClique) = getData(cliql).dwnMsg -getDwnMsgs(btl::BayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) +getDwnMsgs(btl::AbstractBayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) """ $(SIGNATURES) @@ -849,7 +849,7 @@ function setCliqPotentials!(dfg::G, end function getCliquePotentials!(dfg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliq::TreeClique ) where G <: AbstractDFG # @warn "getCliquePotentials! deprecated, use getCliqPotentials instead." @@ -995,7 +995,7 @@ getCliqVarIdsAll, getCliqFactors """ getCliqFactorIdsAll(cliqd::BayesTreeNodeData) = cliqd.potentials getCliqFactorIdsAll(cliq::TreeClique) = getCliqFactorIdsAll(getData(cliq)) -getCliqFactorIdsAll(treel::BayesTree, frtl::Symbol) = getCliqFactorIdsAll(getCliq(treel, frtl)) +getCliqFactorIdsAll(treel::AbstractBayesTree, frtl::Symbol) = getCliqFactorIdsAll(getCliq(treel, frtl)) const getCliqFactors = getCliqFactorIdsAll @@ -1153,7 +1153,7 @@ function compCliqAssocMatrices!(dfg::G, bt::AbstractBayesTree, cliq::TreeClique) end -function countSkips(bt::BayesTree) +function countSkips(bt::AbstractBayesTree) skps = 0 for cliq in bt.cliques m = getCliqMat(cliq[2]) @@ -1374,15 +1374,15 @@ end Return a vector of child cliques to `cliq`. """ -getChildren(treel::BayesTree, frtsym::Symbol) = childCliqs(treel, frtsym) -getChildren(treel::BayesTree, cliq::TreeClique) = childCliqs(treel, cliq) +getChildren(treel::AbstractBayesTree, frtsym::Symbol) = childCliqs(treel, frtsym) +getChildren(treel::AbstractBayesTree, cliq::TreeClique) = childCliqs(treel, cliq) """ $SIGNATURES Return a vector of all siblings to a clique, which defaults to not `inclusive` the calling `cliq`. """ -function getCliqSiblings(treel::BayesTree, cliq::TreeClique, inclusive::Bool=false)::Vector{TreeClique} +function getCliqSiblings(treel::AbstractBayesTree, cliq::TreeClique, inclusive::Bool=false)::Vector{TreeClique} prnt = getParent(treel, cliq) if length(prnt) > 0 allch = getChildren(treel, prnt[1]) @@ -1411,12 +1411,29 @@ function parentCliq(treel::BayesTree, frtsym::Symbol) parentCliq(treel, whichCliq(treel, frtsym)) end +function parentCliq(treel::MetaBayesTree, cliq::TreeClique) + parentcliqs = TreeClique[] + for pIdx in MetaGraphs.inneighbors(treel.bt, cliq.index) + push!(parentcliqs, get_prop(treel.bt, pIdx, :clique)) + end + return parentcliqs +end + +""" + $(SIGNATURES) + +Return number of cliques in a tree. +""" +getNumCliqs(tree::BayesTree) = Graphs.num_vertices(tree.bt) +getNumCliqs(tree::MetaBayesTree) = MetaGraphs.nv(tree.bt) + + """ $(SIGNATURES) Return `cliq`'s parent clique. """ -getParent(treel::BayesTree, afrontal::Union{Symbol, TreeClique}) = parentCliq(treel, afrontal) +getParent(treel::AbstractBayesTree, afrontal::Union{Symbol, TreeClique}) = parentCliq(treel, afrontal) """ $SIGNATURES @@ -1515,9 +1532,9 @@ end Return the variable order stored in a tree object. """ -getVariableOrder(treel::BayesTree)::Vector{Symbol} = treel.variableOrder +getVariableOrder(treel::AbstractBayesTree)::Vector{Symbol} = treel.variableOrder -getEliminationOrder(treel::BayesTree) = treel.variableOrder +getEliminationOrder(treel::AbstractBayesTree) = treel.variableOrder """ @@ -1533,7 +1550,7 @@ Related IIF.loadTree, DFG.saveDFG, DFG.loadDFG, JLD2.@save, JLD2.@load """ -function saveTree(treel::BayesTree, +function saveTree(treel::AbstractBayesTree, filepath=joinpath("/tmp","caesar","savetree.jld2") ) # savetree = deepcopy(treel) diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 5baac0fef..679463311 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -52,16 +52,15 @@ mutable struct BayesTree <: AbstractBayesTree buildTime::Float64 end -function emptyBayesTree() - bt = BayesTree(Graphs.inclist(TreeClique,is_directed=true), - 0, - Dict{Int,TreeClique}(), - #[], - Dict{AbstractString, Int}(), - Symbol[], - 0.0 ) - return bt -end +BayesTree() = BayesTree(Graphs.inclist(TreeClique,is_directed=true), + 0, + Dict{Int,TreeClique}(), + Dict{AbstractString, Int}(), + Symbol[], + 0.0 ) + +#NOTE select type for development +emptyBayesTree() = BayesTree() # emptyBayesTree() = MetaBayesTree() # TODO DEV MetaGraphs bayes tree, will potentially also make a LightBayesTree, CloudBayesTree, @@ -84,7 +83,10 @@ Base.propertynames(x::MetaBayesTree, private::Bool=false) = (:bt, :btid, :clique Base.getproperty(x::MetaBayesTree,f::Symbol) = begin if f == :cliques - @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" + if !(@isdefined getCliquesWarnOnce) + @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" + global getCliquesWarnOnce = true + end d = Dict{Int,Any}() for (k,v) in x.bt.vprops d[k] = v[:clique] @@ -95,6 +97,20 @@ Base.getproperty(x::MetaBayesTree,f::Symbol) = begin end end +function Base.setproperty!(x::MetaBayesTree, f::Symbol, val) + if f == :cliques + if !(@isdefined setCliquesWarnOnce) + @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" + global setCliquesWarnOnce = true + end + for (k,v) in val + set_prop!(x.bt, k, :clique, v) + end + else + setfield!(x,f,val) + end +end + function MetaBayesTree(tree::BayesTree) # create graph from Graphs.jl adjacency_matrix mtree = MetaBayesTree(MetaDiGraph{Int, Float64}(MetaGraphs.SimpleDiGraph(Graphs.adjacency_matrix(tree.bt))), tree.btid, tree.frontals, tree.variableOrder, tree.buildTime) @@ -126,7 +142,7 @@ TODO - remove proceed - more direct clique access (cliq, parent, children), for multi-process solves """ -mutable struct CliqStateMachineContainer{BTND, BT <: AbstractBayesTree, T <: AbstractDFG, InMemG <: InMemoryDFGTypes} +mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMemoryDFGTypes, BT <: AbstractBayesTree} dfg::T cliqSubFg::InMemG tree::BT @@ -172,10 +188,11 @@ function CliqStateMachineContainer(x1::G, x10::Bool, x10aa::Bool, x10aaa::SolverParams, + x10b::Dict{Symbol,String}=Dict{Symbol,String}(), x11::BTND=emptyBTNodeData(), x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} # - CliqStateMachineContainer{BTND}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x10aa,x10aaa,Dict{Symbol,String}(),x11,x13) + CliqStateMachineContainer{BTND, G, typeof(x2), typeof(x3)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x10aa,x10aaa,x10b,x11,x13) end const CSMHistory = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}} @@ -327,7 +344,7 @@ const ExploreTreeTypeLight{T} = FullExploreTreeType{T, Nothing} function ExploreTreeType(fgl::G, - btl::BayesTree, + btl::AbstractBayesTree, vertl::TreeClique, prt::T, msgs::Array{NBPMessage,1} ) where {G <: AbstractDFG, T} diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index fdb677aa8..5dfbd8c09 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -866,7 +866,7 @@ end Update cliq `cliqID` in Bayes (Juction) tree `bt` according to contents of `ddt` -- intended use is to update main clique after a downward belief propagation computation has been completed per clique. """ function updateFGBT!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliqID::Int, drt::DownReturnBPType; dbg::Bool=false, @@ -932,7 +932,7 @@ function updateFGBT!(fg::G, end function updateFGBT!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliqID::Int, urt::UpReturnBPType; dbg::Bool=false, fillcolor::String="" ) where G <: AbstractDFG @@ -946,13 +946,13 @@ end """ $SIGNATURES -Get and return upward belief messages as stored in child cliques from `treel::BayesTree`. +Get and return upward belief messages as stored in child cliques from `treel::AbstractBayesTree`. Notes - Use last parameter to select the return format. """ function getCliqChildMsgsUp(fg_::G, - treel::BayesTree, + treel::AbstractBayesTree, cliq::TreeClique, ::Type{EasyMessage} ) where G <: AbstractDFG # @@ -969,7 +969,7 @@ function getCliqChildMsgsUp(fg_::G, return childmsgs end -function getCliqChildMsgsUp(treel::BayesTree, cliq::TreeClique, ::Type{BallTreeDensity}) +function getCliqChildMsgsUp(treel::AbstractBayesTree, cliq::TreeClique, ::Type{BallTreeDensity}) childmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity,Float64}}}() # Vector{Bool} for child in getChildren(treel, cliq) for (key, bel) in getUpMsgs(child) @@ -993,7 +993,7 @@ Notes - Different from down initialization messages that do calculate new values -- see `prepCliqInitMsgsDown!`. - Basically converts function `getDwnMsgs` from `Dict{Symbol,BallTreeDensity}` to `Dict{Symbol,Vector{BallTreeDensity}}`. """ -function getCliqParentMsgDown(treel::BayesTree, cliq::TreeClique) +function getCliqParentMsgDown(treel::AbstractBayesTree, cliq::TreeClique) downmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity, Float64}}}() for prnt in getParent(treel, cliq) for (key, bel) in getDwnMsgs(prnt) @@ -1021,7 +1021,7 @@ Future - TODO: internal function chain is too long and needs to be refactored for maintainability. """ function approxCliqMarginalUp!(fgl::G, - treel::BayesTree, + treel::AbstractBayesTree, csym::Symbol, onduplicate=true; N::Int=100, @@ -1108,7 +1108,7 @@ Notes - `onduplicate=true` by default internally uses deepcopy of factor graph and Bayes tree, and does **not** update the given objects. Set false to update `fgl` and `treel` during compute. """ function doCliqInferenceUp!(fgl::FactorGraph, - treel::BayesTree, + treel::AbstractBayesTree, csym::Symbol, onduplicate=true; N::Int=100, @@ -1132,7 +1132,7 @@ end # * Can adjust the number of `iters::Int=3` must be performed on the `itervars` of this clique. # """ # function doCliqInferenceUp!(fgl::FactorGraph, -# treel::BayesTree, +# treel::AbstractBayesTree, # cliql::TreeClique; # N::Int=100, # dbg::Bool=false, @@ -1172,7 +1172,7 @@ end Set all up `upsolved` and `downsolved` cliq data flags `to::Bool=false`. """ -function setAllSolveFlags!(treel::BayesTree, to::Bool=false)::Nothing +function setAllSolveFlags!(treel::AbstractBayesTree, to::Bool=false)::Nothing for (id, cliq) in treel.cliques cliqdata = getData(cliq) cliqdata.initialized = :null @@ -1187,7 +1187,7 @@ end Return true or false depending on whether the tree has been fully initialized/solved/marginalized. """ -function isTreeSolved(treel::BayesTree; skipinitialized::Bool=false)::Bool +function isTreeSolved(treel::AbstractBayesTree; skipinitialized::Bool=false)::Bool acclist = Symbol[:upsolved; :downsolved; :marginalized] skipinitialized ? nothing : push!(acclist, :initialized) for (clid, cliq) in treel.cliques @@ -1198,7 +1198,7 @@ function isTreeSolved(treel::BayesTree; skipinitialized::Bool=false)::Bool return true end -function isTreeSolvedUp(treel::BayesTree)::Bool +function isTreeSolvedUp(treel::AbstractBayesTree)::Bool for (clid, cliq) in treel.cliques if getCliqStatus(cliq) != :upsolved return false @@ -1266,7 +1266,7 @@ Notes - Will change previous clique status from `:downsolved` to `:initialized` only. - Sets the color of tree clique to `lightgreen`. """ -function resetTreeCliquesForUpSolve!(treel::BayesTree)::Nothing +function resetTreeCliquesForUpSolve!(treel::AbstractBayesTree)::Nothing acclist = Symbol[:downsolved;] for (clid, cliq) in treel.cliques if getCliqStatus(cliq) in acclist @@ -1280,7 +1280,7 @@ end """ $SIGNATURES -Special internal function to try return the clique data if succesfully identified in `othertree::BayesTree`, +Special internal function to try return the clique data if succesfully identified in `othertree::AbstractBayesTree`, based on contents of `seeksSimilar::BayesTreeNodeData`. Notes @@ -1332,11 +1332,11 @@ end function tryCliqStateMachineSolve!(dfg::G, - treel::BayesTree, + treel::AbstractBayesTree, i::Int; # cliqHistories; N::Int=100, - oldtree::BayesTree=emptyBayesTree(), + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, limititers::Int=-1, downsolve::Bool=false, @@ -1408,7 +1408,7 @@ end After solving, clique histories can be inserted back into the tree for later reference. This function helps do the required assigment task. """ -function assignTreeHistory!(treel::BayesTree, cliqHistories::Dict) +function assignTreeHistory!(treel::AbstractBayesTree, cliqHistories::Dict) for i in 1:length(treel.cliques) if haskey(cliqHistories, i) hist = cliqHistories[i] @@ -1456,7 +1456,7 @@ Related initInferTreeUp! """ function asyncTreeInferUp!(dfg::G, - treel::BayesTree; + treel::AbstractBayesTree; oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, @@ -1513,7 +1513,7 @@ Related asyncTreeInferUp! """ function initInferTreeUp!(dfg::G, - treel::BayesTree; + treel::AbstractBayesTree; oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, diff --git a/src/SolverAPI.jl b/src/SolverAPI.jl index 2b0123729..80069a946 100644 --- a/src/SolverAPI.jl +++ b/src/SolverAPI.jl @@ -53,7 +53,7 @@ function solveTree!(dfgl::G, # transfer new tree to outside parameter oldtree.bt = tree.bt oldtree.btid = tree.btid - oldtree.cliques = tree.cliques + oldtree.cliques = tree.cliques #TODO JT kyk meer detail, this is a bit strange as its a copy of data in graph oldtree.frontals = tree.frontals oldtree.variableOrder = tree.variableOrder oldtree.buildTime = tree.buildTime @@ -116,7 +116,7 @@ Notes - For legacy versions of tree traversal, see `inferOverTreeIterative!` instead. """ function inferOverTree!(dfg::G, - bt::BayesTree; + bt::AbstractBayesTree; oldtree::AbstractBayesTree=emptyBayesTree(), N::Int=100, upsolve::Bool=true, @@ -157,7 +157,7 @@ Notes - Even older code is available as `inferOverTreeR!` """ function inferOverTreeIterative!(dfg::G, - bt::BayesTree; + bt::AbstractBayesTree; N::Int=100, dbg::Bool=false, drawpdf::Bool=false ) where G <: AbstractDFG @@ -179,7 +179,7 @@ end Perform up and down message passing (single process, recursive) algorithm for full sum-product solution of all continuous marginal beliefs. """ function inferOverTreeR!(fgl::G, - bt::BayesTree; + bt::AbstractBayesTree; N::Int=100, dbg::Bool=false, drawpdf::Bool=false, diff --git a/src/SolverUtilities.jl b/src/SolverUtilities.jl index 27c25623d..f4f30d47f 100644 --- a/src/SolverUtilities.jl +++ b/src/SolverUtilities.jl @@ -237,7 +237,7 @@ Dev Notes - TODO not all kde manifolds will initialize to zero. """ function resetCliqSolve!(dfg::G, - treel::BayesTree, + treel::AbstractBayesTree, cliq::TreeClique; solveKey::Symbol=:default)::Nothing where G <: AbstractDFG # @@ -260,7 +260,7 @@ function resetCliqSolve!(dfg::G, end function resetCliqSolve!(dfg::G, - treel::BayesTree, + treel::AbstractBayesTree, frt::Symbol; solveKey::Symbol=:default )::Nothing where G <: AbstractDFG # diff --git a/src/SubGraphFunctions.jl b/src/SubGraphFunctions.jl index 93d878077..0cbb94501 100644 --- a/src/SubGraphFunctions.jl +++ b/src/SubGraphFunctions.jl @@ -44,7 +44,7 @@ Notes - `varsym::Symbol` defaults to the cliq frontal variable definition but can in case a separator variable is required instead. """ -function buildCliqSubgraphDown(fgl::AbstractDFG, treel::BayesTree, cliqsym::Symbol, varsym::Symbol=cliqsym) +function buildCliqSubgraphDown(fgl::AbstractDFG, treel::AbstractBayesTree, cliqsym::Symbol, varsym::Symbol=cliqsym) @warn "Obsolete, buildCliqSubGraph*() is no longer in use" # build a subgraph copy of clique cliq = whichCliq(treel, cliqsym) diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index e7eac2a1d..c8aae4261 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -990,7 +990,7 @@ end Return true or false depending on whether child cliques are all up solved. """ -function areCliqChildrenAllUpSolved(treel::BayesTree, +function areCliqChildrenAllUpSolved(treel::AbstractBayesTree, prnt::TreeClique)::Bool # for ch in getChildren(treel, prnt) diff --git a/test/runtests.jl b/test/runtests.jl index ac1c6c8a1..71401281a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,6 +24,7 @@ include("testPartialFactors.jl") include("testBayesTreeiSAM2Example.jl") end +#FIXME fails on MetaBayesTree include("testTreeSaveLoad.jl") @testset "Ensure converter types can be run from extending namespaces..." begin diff --git a/test/testBayesTreeiSAM2Example.jl b/test/testBayesTreeiSAM2Example.jl index 681828f08..32ef003ad 100644 --- a/test/testBayesTreeiSAM2Example.jl +++ b/test/testBayesTreeiSAM2Example.jl @@ -47,7 +47,7 @@ global tree = emptyBayesTree() buildTree!(tree, fge, p) -@test num_vertices(tree.bt) == 3 +@test getNumCliqs(tree) == 3 # Michael reference -- x2->x1, x2->x3, x2->x4, x2->l1, x4->x3, l1->x3, l1->x4 From f7e9659a7a00c3db21a53cdd670cd50e91f50153 Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Thu, 9 Jan 2020 14:40:41 +0200 Subject: [PATCH 24/57] MetaBayesTree drawing --- src/JunctionTree.jl | 6 ++--- src/JunctionTreeTypes.jl | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 9182294c0..346b61272 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -261,7 +261,7 @@ Notes - Uses system install of graphviz.org. - Can also use Linux tool `xdot`. """ -function drawTree(treel::BayesTree; +function drawTree(treel::AbstractBayesTree; show::Bool=false, # must remain false for stability and automated use in solver filepath::String="/tmp/caesar/bt.pdf", viewerapp::String="evince", @@ -1564,8 +1564,8 @@ function saveTree(treel::AbstractBayesTree, return filepath end -function saveTree(treeArr::Vector{BayesTree}, - filepath=joinpath("/tmp","caesar","savetrees.jld2") ) +function saveTree(treeArr::Vector{T}, + filepath=joinpath("/tmp","caesar","savetrees.jld2") ) where T <: AbstractBayesTree # savetree = deepcopy(treeArr) for savtre in savetree, i in 1:length(savtre.cliques) diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 679463311..990511386 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -132,6 +132,53 @@ function MetaBayesTree(tree::BayesTree) end +# A replacement for to_dot that saves only plotting attributes +function savedot_attributes(io::IO, g::MetaDiGraph) + write(io, "digraph G {\n") + for p in props(g) + write(io, "$(p[1])=$(p[2]);\n") + end + + for v in MetaGraphs.vertices(g) + write(io, "$v") + if length(props(g, v)) > 0 + write(io, " [ ") + end + for p in props(g, v) + # key = p[1] + # write(io, "$key=\"$(p[2])\",") + for (k,v) in p[2] + write(io, "\"$k\"=\"$v\",") + end + end + if length(props(g, v)) > 0 + write(io, "];") + end + write(io, "\n") + end + + for e in MetaGraphs.edges(g) + write(io, "$(MetaGraphs.src(e)) -> $(MetaGraphs.dst(e)) [ ") + # for p in props(g,e) + # write(io, "$(p[1])=$(p[2]), ") + # end + write(io, "]\n") + end + write(io, "}\n") +end + +function Graphs.to_dot(mdigraph::MetaDiGraph) + g = deepcopy(mdigraph) + for (i,val) in g.vprops + push!(g.vprops[i],:attributes=>val[:clique].attributes) + delete!(g.vprops[i],:clique) + end + m = PipeBuffer() + savedot_attributes(m, g) + data = take!(m) + close(m) + return String(data) +end """ $TYPEDEF From f5c8ecdb945ed562b418093f3de8c59f45e6091c Mon Sep 17 00:00:00 2001 From: antonio teran Date: Thu, 9 Jan 2020 19:14:26 -0500 Subject: [PATCH 25/57] Add plots for analysis. --- examples/TreeAnalysis.jl | 54 ++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl index 13bc4106c..8cd564ec6 100644 --- a/examples/TreeAnalysis.jl +++ b/examples/TreeAnalysis.jl @@ -19,7 +19,7 @@ all_trees = getAllTrees(deepcopy(fg)) # scores stores: (tree key ID, nnz, cost fxn 1, cost fxn 2). unsorted_scores = Vector{Tuple{Int, Float64, Float64, Float64}}() for key in keys(all_trees) - e = all_trees[key] # (Bayes tree, var order, nnz) + e = all_trees[key] # (Bayes tree, var order, nnz tree = e[1] # Get the Bayes tree. cost1 = getTreeCost_01(tree) cost2 = getTreeCost_02(tree) @@ -34,11 +34,31 @@ all_nnzs = (x->(x[2])).(scores) costs_01 = (x->(x[3])).(scores) costs_02 = (x->(x[4])).(scores) -bincnt = 20 -Gadfly.plot(x=all_nnzs, y=costs_02, - Geom.hexbin(xbincount=bincnt, ybincount=bincnt), - Guide.xlabel("Number of non zeros [int]"), - Guide.ylabel("Tree cost [cfxn2]")) +# HACKING +# plotting tricks with gadfly +# trick 1 +# using Colors +# PL = [] +# push!(PL, Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"red"))) +# push!(PL, Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"magenta"))) +# # push!(PL, ThemeLege...) +# pl = Gadfly.plot(PL...) +# +# pl |> typeof |> fieldnames +# # fieldnames(typeof(pl)) +# +# pl.coord = Coord.Cartesian(xmin=0,xmax=10,ymin=-5,ymax=2) +# +# pl +# pll = Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"green")) +# union!(pl.layers, pll) +# pl +# pl |> SVG("/tmp/test.svg") +# using Cairo +# pl |> PDF("/tmp/test.pdf") +# pl |> PNG("/tmp/test.png") + + min_ids_02 = findall(x->x == minimum(costs_02), costs_02) max_ids_02 = findall(x->x == maximum(costs_02), costs_02) @@ -75,4 +95,24 @@ ccolamd_tree = buildTreeFromOrdering!(deepcopy(fg), ccolamd_ordering) ccolamd_tree_nnz = nnzTree(ccolamd_tree) ccolamd_tree_cost02 = getTreeCost_02(ccolamd_tree) -# Plot both data points. +# Plot data points and underlying histogram. +bincnt = 20 +layers = [] +push!(layers, Gadfly.layer(x=[amd_tree_nnz], + y=[amd_tree_cost02], + Theme(default_color=colorant"green"))) +push!(layers, Gadfly.layer(x=[colamd_tree_nnz], + y=[colamd_tree_cost02], + Theme(default_color=colorant"blue"))) +push!(layers, Gadfly.layer(x=[ccolamd_tree_nnz], + y=[ccolamd_tree_cost02], + Theme(default_color=colorant"red"))) +push!(layers, Gadfly.layer(x=all_nnzs, + y=costs_02, + Geom.hexbin(xbincount=bincnt, ybincount=bincnt))) +pl = Gadfly.plot(layers..., + Guide.xlabel("Number of non zeros [int]"), + Guide.ylabel("Tree cost [cfxn2]"), + Guide.manual_color_key("", + ["AMD", "COLAMD", "iSAM2"], + ["green", "blue", "red"])) From 828257c1ec1fde41e33f646a8ae931bac908bf7b Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Fri, 10 Jan 2020 13:10:10 +0200 Subject: [PATCH 26/57] most .cliques -> getClique/getCliques --- src/FactorGraph01.jl | 5 +- src/JunctionTree.jl | 91 +++++++++++++++++++++------------- src/JunctionTreeTypes.jl | 10 ++-- src/SolveTree01.jl | 45 ++++++++--------- src/SolverAPI.jl | 8 +-- src/TreeBasedInitialization.jl | 2 +- 6 files changed, 95 insertions(+), 66 deletions(-) diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index cd20a2790..5c2b338ff 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,10 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::TreeClique) = v.data #v.attributes["data"] +function getData(v::TreeClique) + # @warn "getData(v::TreeClique) deprecated, use getCliqueData instead" + getCliqueData(v) +end """ diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 346b61272..bf7340fbe 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -22,35 +22,56 @@ getFrontals(cliqd::Union{TreeClique,BayesTreeNodeData})::Vector{Symbol} = getCli Create a new clique. """ function addClique!(bt::AbstractBayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::TreeClique where G <: AbstractDFG - bt.btid += 1 + bt.btid += 1 #used by Graphs.jl for id + clq = TreeClique(bt.btid, string("Clique", bt.btid)) + setLabel!(clq, "") + + #TODO addClique!(bt, clq), can't we already have the parent here if isa(bt.bt,GenericIncidenceList) - clq = Graphs.add_vertex!(bt.bt, TreeClique(bt.btid,string("Clique",bt.btid))) + Graphs.add_vertex!(bt.bt, clq) bt.cliques[bt.btid] = clq elseif isa(bt.bt, MetaDiGraph) - clq = TreeClique(bt.btid, string("Clique", bt.btid)) MetaGraphs.add_vertex!(bt.bt, :clique, clq) else error("Oops, something went wrong") end - setLabel!(clq, "") - # Specific data container - setData!(clq, emptyBTNodeData()) + # already emptyBTNodeData() in constructor + # setData!(clq, emptyBTNodeData()) appendClique!(bt, bt.btid, dfg, varID, condIDs) return clq end +#NOTE TODO Ideas towards a standard clique interface +#TODO export +export getClique, getCliques, getCliqueIds, getCliqueData + +getClique(tree::AbstractBayesTree, cId::Int)::TreeClique = tree.cliques[cId] + +#TODO +addClique!(tree::AbstractBayesTree, parentCliqId::Int, cliq::TreeClique)::Bool = error("addClique!(tree::AbstractBayesTree, parentCliqId::Int, cliq::TreeClique) not implemented") +updateClique!(tree::AbstractBayesTree, cliq::TreeClique)::Bool = error("updateClique!(tree::AbstractBayesTree, cliq::TreeClique)::Bool not implemented") +deleteClique!(tree::AbstractBayesTree, cId::Int)::TreeClique = error("deleteClique!(tree::AbstractBayesTree, cId::Int)::TreeClique not implemented") + +getCliques(tree::AbstractBayesTree) = tree.cliques +getCliqueIds(tree::AbstractBayesTree) = keys(getCliques(tree)) + +getCliqueData(cliq::TreeClique)::BayesTreeNodeData = cliq.data +getCliqueData(tree::AbstractBayesTree, cId::Int)::BayesTreeNodeData = getClique(tree, cId) |> getCliqueData + + + """ $SIGNATURES Generate the label for particular clique (used by graphviz for visualization). """ function makeCliqueLabel(dfg::G, bt::AbstractBayesTree, clqID::Int)::String where G <: AbstractDFG - clq = bt.cliques[clqID] + clq = getClique(bt, clqID) flbl = "" clbl = "" for fr in getData(clq).frontalIDs @@ -68,7 +89,7 @@ end Add the separator for the newly created clique. """ function appendSeparatorToClique(bt::AbstractBayesTree, clqID::Int, seprIDs::Array{Symbol,1}) - union!(getData(bt.cliques[clqID]).separatorIDs, seprIDs) + union!(getCliqueData(bt, clqID).separatorIDs, seprIDs) nothing end @@ -86,7 +107,7 @@ function appendClique!(bt::AbstractBayesTree, varID::Symbol, seprIDs::Array{Symbol,1}=Symbol[] )::Nothing # - clq = bt.cliques[clqID] #TODO replace with getClique + clq = getClique(bt, clqID) var = DFG.getVariable(dfg, varID) # add frontal variable @@ -108,9 +129,11 @@ end Instantiate a new child clique in the tree. """ function newChildClique!(bt::AbstractBayesTree, dfg::AbstractDFG, CpID::Int, varID::Symbol, Sepj::Array{Symbol,1}) + #TODO this is too manual, replace with just addClique that takes as argument the parent + # addClique!(bt, dfg, CpID, varID, Sepj) # physically create the new clique chclq = addClique!(bt, dfg, varID, Sepj) - parent = bt.cliques[CpID] + parent = getClique(bt,CpID) if isa(bt.bt,GenericIncidenceList) # Staying with Graphs.jl for tree in first stage @@ -133,7 +156,7 @@ end Post order tree traversal and build potential functions """ function findCliqueFromFrontal(bt::AbstractBayesTree, frtlID::Int) - for cliqPair in bt.cliques + for cliqPair in getCliques(bt, cliques) id = cliqPair[1] cliq = cliqPair[2] for frtl in getFrontals(cliq) @@ -185,7 +208,7 @@ function newPotential(tree::AbstractBayesTree, dfg::G, var::Symbol, elimorder::A firvert = DFG.getVariable(dfg,var) # no parent if (length(solverData(firvert).separator) == 0) - # if (length(tree.cliques) == 0) + # if (length(getCliques(tree)) == 0) # create new root addClique!(tree, dfg, var) # else @@ -200,7 +223,7 @@ function newPotential(tree::AbstractBayesTree, dfg::G, var::Symbol, elimorder::A # get clique id of first eliminated frontal CpID = tree.frontals[felbl] # look to add this conditional to the tree - cliq = tree.cliques[CpID] + cliq = getClique(tree, CpID) # clique of the first eliminated frontal unFC = union(getCliqFrontalVarIds(cliq), getCliqSeparatorVarIds(cliq)) # if the separator of this new variable is identical to the (entire) clique of the firstly eliminated frontal. @@ -273,7 +296,7 @@ function drawTree(treel::AbstractBayesTree; # modify a deepcopy btc = deepcopy(treel) - for (cid, cliq) in btc.cliques + for (cid, cliq) in getCliques(btc) if imgs firstlabel = split(getLabel(cliq),',')[1] spyCliqMat(cliq, suppressprint=true) |> exportimg("/tmp/$firstlabel.png") @@ -316,7 +339,7 @@ drawTree function generateTexTree(treel::AbstractBayesTree; filepath::String="/tmp/caesar/bayes/bt") btc = deepcopy(treel) - for (cid, cliq) in btc.cliques + for (cid, cliq) in getCliques(btc) label = getLabel(cliq) # Get frontals and separator, and split into elements. @@ -409,7 +432,7 @@ function buildTreeFromOrdering!(dfg::G, end println("Find potential functions for each clique") - cliq = tree.cliques[1] # start at the root + cliq = getClique(tree, 1) # start at the root #TODO might not always be the root in case of multiple roots and deleted nodes in light graphs? buildCliquePotentials(dfg, tree, cliq, solvable=solvable); # fg does not have the marginals as fge does tree.buildTime = (time_ns()-t0)/1e9 @@ -449,7 +472,7 @@ function buildTreeFromOrdering!(dfg::DFG.AbstractDFG, end println("Find potential functions for each clique") - cliq = tree.cliques[1] # start at the root + cliq = getClique(tree, 1) # start at the root buildCliquePotentials(dfg, tree, cliq); # fg does not have the marginals as fge does return tree @@ -580,7 +603,7 @@ Related: getCliq, getTreeAllFrontalSyms """ -getCliq(bt::AbstractBayesTree, frt::Symbol) = bt.cliques[bt.frontals[frt]] +getCliq(bt::AbstractBayesTree, frt::Symbol) = getClique(bt, bt.frontals[frt]) """ $(SIGNATURES) @@ -1155,7 +1178,7 @@ end function countSkips(bt::AbstractBayesTree) skps = 0 - for cliq in bt.cliques + for cliq in getCliques(bt) m = getCliqMat(cliq[2]) mi = map(Int,m) skps += sum(map(Int,sum(mi, dims=1) .== 1)) @@ -1448,7 +1471,7 @@ Related: whichCliq, printCliqHistorySummary """ function getTreeAllFrontalSyms(fgl::G, tree::AbstractBayesTree) where G <: AbstractDFG - cliqs = tree.cliques + cliqs = getCliques(tree) syms = Vector{Symbol}(undef, length(cliqs)) for (id,cliq) in cliqs syms[id] = getCliqFrontalVarIds(cliq)[1] @@ -1476,7 +1499,7 @@ getUpMsgs """ function getTreeCliqUpMsgsAll(tree::AbstractBayesTree)::Dict{Int,TempBeliefMsg} allUpMsgs = Dict{Int,TempBeliefMsg}() - for (idx,cliq) in tree.cliques + for (idx,cliq) in getCliques(tree) msgs = getUpMsgs(cliq) allUpMsgs[cliq.index] = TempBeliefMsg() for (lbl,msg) in msgs @@ -1517,7 +1540,7 @@ function stackCliqUpMsgsByVariable(tree::AbstractBayesTree, stack[sym] = Vector{Tuple{Symbol, Int, BallTreeDensity, Float64}}() end # assemble metadata - cliq = tree.cliques[cidx] + cliq = getCliques(tree,cidx) frt = getCliqFrontalVarIds(cliq)[1] # add this belief msg and meta data to vector of variable entry push!(stack[sym], (frt, getCliqDepth(tree, cliq),msgdim[1], msgdim[2])) @@ -1554,9 +1577,9 @@ function saveTree(treel::AbstractBayesTree, filepath=joinpath("/tmp","caesar","savetree.jld2") ) # savetree = deepcopy(treel) - for i in 1:length(savetree.cliques) - if getData(savetree.cliques[i]) isa BayesTreeNodeData - setData!(savetree.cliques[i], convert(PackedBayesTreeNodeData, getData(savetree.cliques[i]))) + for i in 1:length(getCliques(savetree)) + if getCliqueData(savetree, i) isa BayesTreeNodeData + setData!(getClique(savetree, i), convert(PackedBayesTreeNodeData, getCliqueData(savetree, i))) end end @@ -1568,9 +1591,9 @@ function saveTree(treeArr::Vector{T}, filepath=joinpath("/tmp","caesar","savetrees.jld2") ) where T <: AbstractBayesTree # savetree = deepcopy(treeArr) - for savtre in savetree, i in 1:length(savtre.cliques) - if getData(savtre.cliques[i]) isa BayesTreeNodeData - setData!(savtre.cliques[i], convert(PackedBayesTreeNodeData, getData(savtre.cliques[i]))) + for savtre in savetree, i in 1:length(getCliques(savtre)) + if getCliqueData(savtre, i) isa BayesTreeNodeData + setData!(getClique(savtre,i), convert(PackedBayesTreeNodeData, getCliqueData(savtre, i))) end end @@ -1596,15 +1619,15 @@ function loadTree(filepath=joinpath("/tmp","caesar","savetree.jld2")) # convert back to a type that which could not be serialized by JLD2 if savetree isa Vector - for savtre in savetree, i in 1:length(savtre.cliques) - if getData(savtre.cliques[i]) isa PackedBayesTreeNodeData - setData!(savtre.cliques[i], convert(BayesTreeNodeData, getData(savtre.cliques[i]))) + for savtre in savetree, i in 1:length(getCliques(savtre)) + if getCliqueData(savtre, i) isa PackedBayesTreeNodeData + setData!(getClique(savtre, i), convert(BayesTreeNodeData, getCliqueData(savtre, i))) end end else - for i in 1:length(savetree.cliques) - if getData(savetree.cliques[i]) isa PackedBayesTreeNodeData - setData!(savetree.cliques[i], convert(BayesTreeNodeData, getData(savetree.cliques[i]))) + for i in 1:length(getCliques(savetree)) + if getCliqueData(savetree, i) isa PackedBayesTreeNodeData + setData!(getClique(savetree, i), convert(BayesTreeNodeData, getCliqueData(savetree, i))) end end end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 990511386..87cdda464 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -9,10 +9,14 @@ DEV NOTES: To replace TreeClique completely $(FIELDS) """ mutable struct TreeClique - index::Int - label::Symbol - data::Any #BayesTreeNodeData #FIXME There is circular type usage in TreeClique, BayesTreeNodeData, CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 + index::Int #TODO maybe depricate with Graphs.jl, or use as an unique identifier + #do not use directly as graph index as it complicates keeping the index in sync with the graph + #it may be useful with a db graph? _index + label::Symbol # this is currently a label such as clique 1, It or index may be usefull as an unique identifier such as a counter or an autogenerated GUID. + # The drawing label is saved in attributes, JT I'm not sure of the current use + data::Any#BayesTreeNodeData #FIXME There is circular type usage in TreeClique, BayesTreeNodeData, CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 attributes::Dict{String, Any} #The drawing attributes + #solveInProgress #on a clique level a "solve in progress" might be very handy end TreeClique(i::Int, label::Symbol) = TreeClique(i, label, emptyBTNodeData(), Dict{String,Any}()) diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 5dfbd8c09..d842459af 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -873,7 +873,7 @@ function updateFGBT!(fg::G, fillcolor::String="", logger=ConsoleLogger() ) where G <: AbstractDFG # - cliq = bt.cliques[cliqID] + cliq = getClique(bt, cliqID) # if dbg # cliq.attributes["debugDwn"] = deepcopy(drt.dbgDwn) # end @@ -937,8 +937,7 @@ function updateFGBT!(fg::G, urt::UpReturnBPType; dbg::Bool=false, fillcolor::String="" ) where G <: AbstractDFG # - cliq = bt.cliques[cliqID] - cliq = bt.cliques[cliqID] + cliq = getClique(bt, cliqID) updateFGBT!( fg, cliq, urt, dbg=dbg, fillcolor=fillcolor ) end @@ -1039,10 +1038,10 @@ function approxCliqMarginalUp!(fgl::G, tree_ = onduplicate ? wipeBuildNewTree!(fgl) : treel - # copy up and down msgs that may already exists + # copy up and down msgs that may already exists #TODO Exists where? it copies from tree_ to tree if onduplicate for (id, cliq) in tree_.cliques - setUpMsg!(tree_.cliques[cliq.index], getUpMsgs(cliq)) + setUpMsg!(tree_.cliques[cliq.index], getUpMsgs(cliq)) #TODO cliq.index may be problematic, how do we know it will be the same index on rebuilding? setDwnMsg!(tree_.cliques[cliq.index], getDwnMsgs(cliq)) end end @@ -1173,7 +1172,7 @@ end Set all up `upsolved` and `downsolved` cliq data flags `to::Bool=false`. """ function setAllSolveFlags!(treel::AbstractBayesTree, to::Bool=false)::Nothing - for (id, cliq) in treel.cliques + for (id, cliq) in getCliques(treel) cliqdata = getData(cliq) cliqdata.initialized = :null cliqdata.upsolved = to @@ -1190,7 +1189,7 @@ Return true or false depending on whether the tree has been fully initialized/so function isTreeSolved(treel::AbstractBayesTree; skipinitialized::Bool=false)::Bool acclist = Symbol[:upsolved; :downsolved; :marginalized] skipinitialized ? nothing : push!(acclist, :initialized) - for (clid, cliq) in treel.cliques + for (clid, cliq) in getCliques(treel) if !(getCliqStatus(cliq) in acclist) return false end @@ -1199,7 +1198,7 @@ function isTreeSolved(treel::AbstractBayesTree; skipinitialized::Bool=false)::Bo end function isTreeSolvedUp(treel::AbstractBayesTree)::Bool - for (clid, cliq) in treel.cliques + for (clid, cliq) in getCliques(treel) if getCliqStatus(cliq) != :upsolved return false end @@ -1249,7 +1248,7 @@ Notes: - TODO can be made fully parallel, consider converting for use with `@threads` `for`. """ function updateTreeCliquesAsMarginalizedFromVars!(fgl::FactorGraph, tree::AbstractBayesTree)::Nothing - for (clid, cliq) in tree.cliques + for (clid, cliq) in getCliques(tree) if isCliqMarginalizedFromVars(fgl, cliq) setCliqAsMarginalized!(cliq, true) end @@ -1268,7 +1267,7 @@ Notes """ function resetTreeCliquesForUpSolve!(treel::AbstractBayesTree)::Nothing acclist = Symbol[:downsolved;] - for (clid, cliq) in treel.cliques + for (clid, cliq) in getCliques(treel) if getCliqStatus(cliq) in acclist setCliqStatus!(cliq, :initialized) setCliqDrawColor(cliq, "sienna") @@ -1345,7 +1344,7 @@ function tryCliqStateMachineSolve!(dfg::G, recordcliqs::Vector{Symbol}=Symbol[]) where G <: AbstractDFG # clst = :na - cliq = treel.cliques[i] + cliq = getClique(treel, i) syms = getCliqFrontalVarIds(cliq) # ids = oldcliq = attemptTreeSimilarClique(oldtree, getData(cliq)) oldcliqdata = getData(oldcliq) @@ -1409,13 +1408,13 @@ After solving, clique histories can be inserted back into the tree for later ref This function helps do the required assigment task. """ function assignTreeHistory!(treel::AbstractBayesTree, cliqHistories::Dict) - for i in 1:length(treel.cliques) + for i in 1:length(getCliques(treel)) if haskey(cliqHistories, i) hist = cliqHistories[i] for i in 1:length(hist) hist[i][4].logger = SimpleLogger(stdout) end - getData(treel.cliques[i]).statehistory=hist + getCliqueData(treel, i).statehistory=hist end end end @@ -1475,13 +1474,13 @@ function asyncTreeInferUp!(dfg::G, end # queue all the tasks - alltasks = Vector{Task}(undef, length(treel.cliques)) + alltasks = Vector{Task}(undef, length(getCliques(treel))) # cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}() if !isTreeSolved(treel, skipinitialized=true) # @sync begin # duplicate int i into async (important for concurrency) - for i in 1:length(treel.cliques) - scsym = getCliqFrontalVarIds(treel.cliques[i]) + for i in 1:length(getCliques(treel)) + scsym = getCliqFrontalVarIds(getClique(treel, i)) if length(intersect(scsym, skipcliqids)) == 0 alltasks[i] = @async tryCliqStateMachineSolve!(dfg, treel, i, oldtree=oldtree, drawtree=drawtree, limititers=limititers, downsolve=downsolve, delaycliqs=delaycliqs, recordcliqs=recordcliqs, incremental=incremental, N=N) end # if @@ -1492,9 +1491,9 @@ function asyncTreeInferUp!(dfg::G, # post-hoc store possible state machine history in clique (without recursively saving earlier history inside state history) # assignTreeHistory!(treel, cliqHistories) - # for i in 1:length(treel.cliques) + # for i in 1:length(getCliques(treel)) # if haskey(cliqHistories, i) - # getData(treel.cliques[i]).statehistory=cliqHistories[i] + # getCliqueData(treel, i).statehistory=cliqHistories[i] # end # end @@ -1530,13 +1529,13 @@ function initInferTreeUp!(dfg::G, drawtree ? drawTree(treel, show=false, filepath=joinpath(getSolverParams(dfg).logpath,"bt.pdf")) : nothing # queue all the tasks - alltasks = Vector{Task}(undef, length(treel.cliques)) + alltasks = Vector{Task}(undef, length(getCliques(treel))) cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}() if !isTreeSolved(treel, skipinitialized=true) @sync begin # duplicate int i into async (important for concurrency) - for i in 1:length(treel.cliques) - scsym = getCliqFrontalVarIds(treel.cliques[i]) + for i in 1:length(getCliques(treel)) + scsym = getCliqFrontalVarIds(getClique(treel, i)) if length(intersect(scsym, skipcliqids)) == 0 alltasks[i] = @async tryCliqStateMachineSolve!(dfg, treel, i, oldtree=oldtree, drawtree=drawtree, limititers=limititers, downsolve=downsolve, incremental=incremental, delaycliqs=delaycliqs, recordcliqs=recordcliqs, N=N) end # if @@ -1548,13 +1547,13 @@ function initInferTreeUp!(dfg::G, # post-hoc store possible state machine history in clique (without recursively saving earlier history inside state history) assignTreeHistory!(treel, cliqHistories) - # for i in 1:length(treel.cliques) + # for i in 1:length(getCliques(treel)) # if haskey(cliqHistories, i) # hist = cliqHistories[i] # for i in 1:length(hist) # hist[i][4].logger = ConsoleLogger() # end - # getData(treel.cliques[i]).statehistory=hist + # getCliqueData(treel,i).statehistory=hist # end # end diff --git a/src/SolverAPI.jl b/src/SolverAPI.jl index 80069a946..65c24a1b5 100644 --- a/src/SolverAPI.jl +++ b/src/SolverAPI.jl @@ -167,9 +167,9 @@ function inferOverTreeIterative!(dfg::G, @info "Ensure all nodes are initialized" ensureAllInitialized!(dfg) @info "Do multi-process upward pass of inference on tree" - upMsgPassingIterative!(ExploreTreeType(dfg, bt, bt.cliques[1], nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); + upMsgPassingIterative!(ExploreTreeType(dfg, bt, getClique(bt, 1), nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); @info "Do multi-process downward pass of inference on tree" - downMsgPassingIterative!(ExploreTreeType(dfg, bt, bt.cliques[1], nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); + downMsgPassingIterative!(ExploreTreeType(dfg, bt, getClique(bt, 1), nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); return smtasks, ch end @@ -195,10 +195,10 @@ function inferOverTreeR!(fgl::G, else @info "Do conventional recursive up inference over tree" ensureAllInitialized!(fgl) - upMsgPassingRecursive(ExploreTreeType(fgl, bt, bt.cliques[1], nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); + upMsgPassingRecursive(ExploreTreeType(fgl, bt, getClique(bt, 1), nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); end @info "Do recursive down inference over tree" - downMsgPassingRecursive(ExploreTreeType(fgl, bt, bt.cliques[1], nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); + downMsgPassingRecursive(ExploreTreeType(fgl, bt, getClique(bt, 1), nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); return smtasks, ch end diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index c8aae4261..4e419ef04 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -286,7 +286,7 @@ Set all Bayes (Junction) tree cliques that have all marginalized and initialized function setTreeCliquesMarginalized!(dfg::G, tree::AbstractBayesTree) where G <: AbstractDFG # - for (cliid, cliq) in tree.cliques + for (cliid, cliq) in getCliques(tree) if areCliqVariablesAllMarginalized(dfg, cliq) # need to set the upward messages msgs = prepCliqInitMsgsUp(dfg, cliq) From f2c6fbcc758b03d624075c5255a92e2fb1b72c2d Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 10 Jan 2020 15:36:29 +0100 Subject: [PATCH 27/57] fix typo in compat section --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e53ad338d..5b4548457 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,7 @@ JLD2 = "0.1, 0.2, 0.3, 1.0" JSON2 = "0.3, 0.4, 0.5, 0.6, 0.7, 1" KernelDensityEstimate = "0.5.1, 0.6" NLsolve = "3, 4" -Optim = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23 1" +Optim = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 1" ProgressMeter = "0.6, 0.7, 0.8, 0.9, 1" Reexport = "0.2, 0.3, 0.4, 0.5, 1" Requires = "0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 1" From 0aca37b722d380108c87174c26af7cbc569e57db Mon Sep 17 00:00:00 2001 From: dehann Date: Sat, 11 Jan 2020 10:31:10 -0500 Subject: [PATCH 28/57] Create CompatHelper.yml --- .github/workflows/CompatHelper.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/CompatHelper.yml diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 000000000..6992ce6b9 --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,24 @@ +name: CompatHelper + +on: + schedule: + - cron: '00 00 * * *' + +jobs: + CompatHelper: + runs-on: ${{ matrix.os }} + strategy: + matrix: + julia-version: [1.2.0] + julia-arch: [x86] + os: [ubuntu-latest] + steps: + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.julia-version }} + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: julia -e 'using CompatHelper; CompatHelper.main()' From 082c30a9f5d8d02de27cf364b2b4e34bbeec1346 Mon Sep 17 00:00:00 2001 From: dehann Date: Sat, 11 Jan 2020 23:10:10 -0500 Subject: [PATCH 29/57] once per day taken from Images.jl --- .github/workflows/CompatHelper.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 6992ce6b9..678fb476f 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -2,7 +2,9 @@ name: CompatHelper on: schedule: - - cron: '00 00 * * *' + - cron: '20 00 * * *' + issues: + types: [opened, reopened] jobs: CompatHelper: From a7746a2c6a7bd02ab8fe78227ed82fed816ff4f8 Mon Sep 17 00:00:00 2001 From: dehann Date: Sun, 12 Jan 2020 00:08:36 -0500 Subject: [PATCH 30/57] add analysis tools to the test suite --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index ac1c6c8a1..b6caafcc9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -81,6 +81,8 @@ end include("fourdoortest.jl") end +include("testAnalysisTools.jl") + @testset "saving to and loading from FileDFG" begin saveFolder = "/tmp/dfg_test" saveDFG(fg, saveFolder) From 18ad1a82e7f62710902fc7d74c69b1cef391e02b Mon Sep 17 00:00:00 2001 From: Johannes Terblanche Date: Wed, 15 Jan 2020 14:12:24 +0200 Subject: [PATCH 31/57] Bugfix for orphaned trees to start from all roots (#533) Merged master and bugfix shows too many changes, so I'm merging to branch so you can compare to master --- .github/workflows/CompatHelper.yml | 26 ++ .gitignore | 2 + Project.toml | 4 +- src/AdditionalUtils.jl | 6 +- src/CanonicalGraphExamples.jl | 70 +++++- src/CliqStateMachine.jl | 16 +- src/CliqStateMachineUtils.jl | 72 +++--- src/Deprecated.jl | 116 ++++----- src/DispatchPackedConversions.jl | 4 +- src/FactorGraph01.jl | 28 ++- src/IncrementalInference.jl | 12 +- src/InferDimensionUtils.jl | 14 +- src/JunctionTree.jl | 340 ++++++++++++++++---------- src/JunctionTreeTypes.jl | 240 ++++++++++++++---- src/SolveTree01.jl | 139 ++++++----- src/SolverAPI.jl | 26 +- src/SolverUtilities.jl | 6 +- src/SubGraphFunctions.jl | 2 +- src/TreeBasedInitialization.jl | 98 ++++---- test/runtests.jl | 3 +- test/testBasicGraphs.jl | 4 +- test/testBayesTreeiSAM2Example.jl | 2 +- test/testSolveOrphanedFG.jl | 4 +- test/unittests/FactorGraph01_tests.jl | 2 +- 24 files changed, 785 insertions(+), 451 deletions(-) create mode 100644 .github/workflows/CompatHelper.yml diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 000000000..678fb476f --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,26 @@ +name: CompatHelper + +on: + schedule: + - cron: '20 00 * * *' + issues: + types: [opened, reopened] + +jobs: + CompatHelper: + runs-on: ${{ matrix.os }} + strategy: + matrix: + julia-version: [1.2.0] + julia-arch: [x86] + os: [ubuntu-latest] + steps: + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.julia-version }} + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.gitignore b/.gitignore index 0ed720739..96de1928a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ test/tmp/*.dot test/tmp/*.tex Manifest.toml + +dev diff --git a/Project.toml b/Project.toml index e53ad338d..6d0d5f92a 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,7 @@ JSON2 = "2535ab7d-5cd8-5a07-80ac-9b1792aadce3" KernelDensityEstimate = "2472808a-b354-52ea-a80e-1658a3c6056d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +MetaGraphs = "626554b9-1ddb-594c-aa3c-2596fe9399a5" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" Optim = "429524aa-4258-5aef-a3af-852621145aeb" ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" @@ -42,8 +43,9 @@ Graphs = "0.10.2, 0.11, 1" JLD2 = "0.1, 0.2, 0.3, 1.0" JSON2 = "0.3, 0.4, 0.5, 0.6, 0.7, 1" KernelDensityEstimate = "0.5.1, 0.6" +MetaGraphs = "0.6.4" NLsolve = "3, 4" -Optim = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23 1" +Optim = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 1" ProgressMeter = "0.6, 0.7, 0.8, 0.9, 1" Reexport = "0.2, 0.3, 0.4, 0.5, 1" Requires = "0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 1" diff --git a/src/AdditionalUtils.jl b/src/AdditionalUtils.jl index 4afcaed76..54b8b233a 100644 --- a/src/AdditionalUtils.jl +++ b/src/AdditionalUtils.jl @@ -14,7 +14,7 @@ Related drawGraphCliq, spyCliqMat, drawTree, buildCliqSubgraphUp, buildSubgraphFromLabels! """ function drawCliqSubgraphUpMocking(fgl::G, - treel::BayesTree, + treel::AbstractBayesTree, frontalSym::Symbol; show::Bool=true, filepath::String="/tmp/cliq_sfg.pdf", @@ -57,7 +57,7 @@ drawCliqSubgraphUpMocking, drawGraph, drawTree """ function drawGraphCliq(hists::Dict{Int, <: Tuple}, step::Int, - tree::BayesTree, + tree::AbstractBayesTree, frontal::Symbol; show::Bool=true ) # @@ -77,7 +77,7 @@ Related printCliqHistorySummary """ function printCliqSummary(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger() ) where G <: AbstractDFG # frtl = getCliqFrontalVarIds(cliq) diff --git a/src/CanonicalGraphExamples.jl b/src/CanonicalGraphExamples.jl index 8892e2865..4fd1db102 100644 --- a/src/CanonicalGraphExamples.jl +++ b/src/CanonicalGraphExamples.jl @@ -1,6 +1,5 @@ -export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D - +export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D, generateCanonicalFG_lineStep """ $SIGNATURES @@ -104,3 +103,70 @@ function loadCanonicalFG_CaesarRing1D(;graphinit::Bool=false) return fg end + + + +""" + $SIGNATURES +Continuous, linear scalar and multivariate test graph generation. Follows a line +with the pose id equal to the ground truth. +""" +function generateCanonicalFG_lineStep(lineLength::Int; + poseEvery::Int=2, + landmarkEvery::Int=4, + posePriorsAt = Int[0], + landmarkPriorsAt = Int[], + sightDistance::Int=4, + vardims = 1, + noisy = false, + graphinit = false, + σ_pose_prior = 0.1, + σ_lm_prior = 0.1, + σ_pose_pose = 0.1, + σ_pose_lm = 0.1, + params=SolverParams()) + # params=SolverParams(algorithms=[:default, :parametric])) + + vtype = (vardims == 1) ? ContinuousScalar() : ContinuousMultivariate(vardims) + + fg = LightDFG{SolverParams}( params=params) + # fg = GraphsDFG{SolverParams}( params=params) + + function xNoise(i::Int, σ::Float64=1.0) + if (vardims == 1) + return noisy ? Normal(σ*randn() + i, σ) : Normal(0.0*randn() + i, σ) + else + return noisy ? MvNormal(σ*randn(vardims) .+ i, σ) : MvNormal(0.0*randn(vardims) .+ i, σ) + end + end + + x = Int[] + lm = Int[] + for i=0:lineLength + if mod(i,poseEvery) == 0 + push!(x, i) + addVariable!(fg, Symbol("x",i), vtype, autoinit = graphinit) + (i in posePriorsAt) && addFactor!(fg, [Symbol("x",i)], Prior(xNoise(i, σ_pose_prior))) + # "odo" type + (i > 0) && addFactor!(fg, [Symbol("x",i-poseEvery); Symbol("x",i)], LinearConditional(xNoise(poseEvery, σ_pose_pose))) + end + + + if landmarkEvery != 0 && mod(i,landmarkEvery) == 0 + push!(lm, i) + addVariable!(fg, Symbol("lm",i), vtype, autoinit = graphinit) + (i in landmarkPriorsAt) && addFactor!(fg, [Symbol("lm",i)], Prior(xNoise(i, σ_lm_prior))) + end + end + + #add landmarks sightings + for xi in x, lmi in lm + dist = lmi - xi + if abs(dist) < sightDistance + # @info "adding landmark lm$lmi to x$xi with dist $dist" + addFactor!(fg, [Symbol("x",xi); Symbol("lm",lmi)], LinearConditional(xNoise(dist, σ_pose_lm))) + end + end + + return fg +end diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 9aaab477c..3c07c156d 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -11,7 +11,7 @@ function infocsm(csmc::CliqStateMachineContainer, str::A) where {A <: AbstractSt tm = string(Dates.now()) tmt = split(tm, 'T')[end] - lbl = csmc.cliq.attributes["label"] + lbl = getLabel(csmc.cliq) lbl1 = split(lbl,',')[1] cliqst = getCliqStatus(csmc.cliq) @@ -845,10 +845,10 @@ Notes: - Doesn't do partial initialized state properly yet. """ function cliqInitSolveUpByStateMachine!(dfg::G, - tree::BayesTree, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + cliq::TreeClique; N::Int=100, - oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), + oldcliqdata::BayesTreeNodeData=emptyBTNodeData(), drawtree::Bool=false, show::Bool=false, incremental::Bool=true, @@ -859,16 +859,14 @@ function cliqInitSolveUpByStateMachine!(dfg::G, delay::Bool=false, logger::SimpleLogger=SimpleLogger(Base.stdout)) where {G <: AbstractDFG, AL <: AbstractLogger} # - children = Graphs.ExVertex[] - for ch in Graphs.out_neighbors(cliq, tree.bt) - push!(children, ch) - end + children = getChildren(tree, cliq)#Graphs.out_neighbors(cliq, tree.bt) + prnt = getParent(tree, cliq) destType = (G <: InMemoryDFGTypes) ? G : InMemDFGType#GraphsDFG{SolverParams} #csmc = CliqStateMachineContainer(dfg, initfg(destType), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), oldcliqdata, logger) - csmc = CliqStateMachineContainer(dfg, initfg(destType, params=getSolverParams(dfg)), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), oldcliqdata, logger) + csmc = CliqStateMachineContainer(dfg, initfg(destType, params=getSolverParams(dfg)), tree, cliq, prnt, children, false, incremental, drawtree, downsolve, delay, getSolverParams(dfg), Dict{Symbol,String}(), oldcliqdata, logger) nxt = upsolve ? testCliqCanRecycled_StateMachine : (downsolve ? testCliqCanRecycled_StateMachine : error("must attempt either up or down solve")) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index ec6edee14..2b8868a57 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -1,4 +1,3 @@ - """ $SIGNATURES @@ -31,7 +30,7 @@ end Return dict of all histories in a Bayes Tree. """ function getTreeCliqsSolverHistories(fg::G, - tree::BayesTree)::Dict{Symbol, CSMHistory} where G <: AbstractDFG + tree::AbstractBayesTree)::Dict{Symbol, CSMHistory} where G <: AbstractDFG # fsy = getTreeAllFrontalSyms(fg, tree) histories = Dict{Symbol, CSMHistory}() @@ -53,10 +52,10 @@ Return clique state machine history from `tree` if it was solved with `recordcli Notes - Cliques are identified by front variable `::Symbol` which are always unique across the cliques. """ -function getCliqSolveHistory(cliq::Graphs.ExVertex) +function getCliqSolveHistory(cliq::TreeClique) getData(cliq).statehistory end -function getCliqSolveHistory(tree::BayesTree, frntal::Symbol) +function getCliqSolveHistory(tree::AbstractBayesTree, frntal::Symbol) cliq = whichCliq(tree, frntal) getCliqSolveHistory(cliq) end @@ -113,18 +112,18 @@ function printCliqHistorySummary(hist::Vector{Tuple{DateTime, Int, Function, Cli printCliqHistorySummary(stdout, hist) end -function printCliqHistorySummary(hists::Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}, tree::BayesTree, sym::Symbol) +function printCliqHistorySummary(hists::Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}, tree::AbstractBayesTree, sym::Symbol) hist = hists[getCliq(tree, sym).index] printCliqHistorySummary(stdout, hist) end -function printCliqHistorySummary(cliq::Graphs.ExVertex) +function printCliqHistorySummary(cliq::TreeClique) hist = getCliqSolveHistory(cliq) printCliqHistorySummary(hist) end -function printCliqHistorySummary(tree::BayesTree, frontal::Symbol) +function printCliqHistorySummary(tree::AbstractBayesTree, frontal::Symbol) hist = getCliqSolveHistory(tree, frontal) printCliqHistorySummary(hist) end @@ -137,7 +136,7 @@ Repeat a solver state machine step without changing history or primary values. printCliqSummary, printCliqHistorySummary, getCliqSolveHistory, cliqHistFilterTransitions """ -function sandboxCliqResolveStep(tree::BayesTree, +function sandboxCliqResolveStep(tree::AbstractBayesTree, frontal::Symbol, step::Int) # @@ -166,7 +165,7 @@ Related printCliqHistorySummary """ -function animateCliqStateMachines(tree::BayesTree, +function animateCliqStateMachines(tree::AbstractBayesTree, cliqsyms::Vector{Symbol}; frames::Int=100 ) # @@ -228,7 +227,7 @@ Related: getCliqSolveHistory, printCliqHistorySummary, cliqHistFilterTransitions, sandboxCliqResolveStep """ -function filterHistAllToArray(tree::BayesTree, frontals::Vector{Symbol}, nextfnc::Function) +function filterHistAllToArray(tree::AbstractBayesTree, frontals::Vector{Symbol}, nextfnc::Function) ret = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}() for sym in frontals hist = getCliqSolveHistory(tree, sym) @@ -250,7 +249,7 @@ Related: initInferTreeUp! """ function solveCliqWithStateMachine!(dfg::G, - tree::BayesTree, + tree::AbstractBayesTree, frontal::Symbol; iters::Int=200, downsolve::Bool=true, @@ -260,10 +259,9 @@ function solveCliqWithStateMachine!(dfg::G, prevcsmc::Union{Nothing,CliqStateMachineContainer}=nothing) where G <: AbstractDFG # cliq = whichCliq(tree, frontal) - children = Graphs.ExVertex[] - for ch in Graphs.out_neighbors(cliq, tree.bt) - push!(children, ch) - end + + children = getChildren(tree, cliq)#Graphs.out_neighbors(cliq, tree.bt) + prnt = getParent(tree, cliq) destType = (G <: InMemoryDFGTypes) ? G : InMemDFGType#GraphsDFG{SolverParams} @@ -313,7 +311,7 @@ run(`vlc /tmp/caesar/csmCompound/out.mp4`) ``` """ function csmAnimate(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqsyms::Vector{Symbol}; frames::Int=100, rmfirst::Bool=true ) where G <: AbstractDFG @@ -362,7 +360,7 @@ Related csmAnimate, printCliqHistorySummary """ function makeCsmMovie(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqs=ls(fg); assignhist=nothing, show::Bool=true, @@ -397,7 +395,7 @@ Dev Notes - Very closely related to getCliqSiblingsPartialNeeds -- refactor likely (NOTE). - should precompute `allinters`. """ -function getSiblingsDelayOrder(tree::BayesTree, cliq::Graphs.ExVertex, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getSiblingsDelayOrder(tree::AbstractBayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # when is a cliq upsolved solvedstats = Symbol[:upsolved; :marginalized; :uprecycled] @@ -489,7 +487,7 @@ function getSiblingsDelayOrder(tree::BayesTree, cliq::Graphs.ExVertex, prnt, dwi end if rows[sibidx] == minimum(rows[maxcan]) with_logger(logger) do - @info "getSiblingsDelayOrder -- FORCE DOWN INIT SOLVE ON THIS CLIQUE: $(cliq.index), $(cliq.attributes["label"])" + @info "getSiblingsDelayOrder -- FORCE DOWN INIT SOLVE ON THIS CLIQUE: $(cliq.index), $(getLabel(cliq))" end return false end @@ -546,7 +544,7 @@ Determine clique truely isn't able to proceed any further: - change status to :mustinitdown if have only partial beliefs so far: - combination of status, while partials belief siblings are not :mustinitdown """ -function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::Graphs.ExVertex, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) +function getCliqSiblingsPartialNeeds(tree::AbstractBayesTree, cliq::TreeClique, prnt, dwinmsgs::Dict; logger=ConsoleLogger()) # which incoming messages are partials hasPartials = Dict{Symbol, Int}() for (sym, tmsg) in dwinmsgs @@ -571,7 +569,7 @@ function getCliqSiblingsPartialNeeds(tree::BayesTree, cliq::Graphs.ExVertex, prn localsep = getCliqSeparatorVarIds(cliq) seps = Dict{Int, Vector{Symbol}}() for si in sibs - # @show si.attributes["label"] + # @show getLabel(si) mighthave = intersect(getCliqSeparatorVarIds(si), localsep) if length(mighthave) > 0 seps[si.index] = mighthave @@ -597,7 +595,7 @@ end Bump a clique state machine solver condition in case a task might be waiting on it. """ -notifyCSMCondition(tree::BayesTree, frsym::Symbol) = notify(getSolveCondition(whichCliq(tree, frsym))) +notifyCSMCondition(tree::AbstractBayesTree, frsym::Symbol) = notify(getSolveCondition(whichCliq(tree, frsym))) """ @@ -605,7 +603,7 @@ notifyCSMCondition(tree::BayesTree, frsym::Symbol) = notify(getSolveCondition(wh Store/cache a clique's solvable dimensions. """ -function updateCliqSolvableDims!(cliq::Graphs.ExVertex, +function updateCliqSolvableDims!(cliq::TreeClique, sdims::Dict{Symbol, Float64}, logger=ConsoleLogger() )::Nothing # @@ -628,7 +626,7 @@ end Retrieve a clique's cached solvable dimensions (since last update). """ -function fetchCliqSolvableDims(cliq::Graphs.ExVertex)::Dict{Symbol,Float64} +function fetchCliqSolvableDims(cliq::TreeClique)::Dict{Symbol,Float64} cliqd = getData(cliq) if isready(cliqd.solvableDims) return cliqd.solvableDims.data[1] @@ -647,8 +645,8 @@ Notes - Relies on sibling priority order with only one "currently best" option that will force progress in global upward inference. - Return false if one of the siblings is still busy """ -function areSiblingsRemaingNeedDownOnly(tree::BayesTree, - cliq::Graphs.ExVertex )::Bool +function areSiblingsRemaingNeedDownOnly(tree::AbstractBayesTree, + cliq::TreeClique )::Bool # stillbusylist = [:null; :initialized;] prnt = getParent(tree, cliq) @@ -724,11 +722,11 @@ Related getGraphFromHistory, printCliqHistorySummary, printCliqSummary """ getCliqSubgraphFromHistory(hist::Vector{<:Tuple}, step::Int) = hist[step][4].cliqSubFg -getCliqSubgraphFromHistory(tree::BayesTree, frnt::Symbol, step::Int) = getCliqSubgraphFromHistory(getCliqSolveHistory(tree, frnt), step) +getCliqSubgraphFromHistory(tree::AbstractBayesTree, frnt::Symbol, step::Int) = getCliqSubgraphFromHistory(getCliqSolveHistory(tree, frnt), step) function printCliqSummary(dfg::G, - tree::BayesTree, + tree::AbstractBayesTree, frs::Symbol, logger=ConsoleLogger() ) where G <: AbstractDFG # @@ -797,7 +795,7 @@ Dev Notes """ function addDownVariableFactors!(dfg::G1, subfg::G2, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger(); solvable::Int=1 ) where {G1 <: AbstractDFG, G2 <: InMemoryDFGTypes} # @@ -849,7 +847,7 @@ end Calculate new and then set the down messages for a clique in Bayes (Junction) tree. """ function getSetDownMessagesComplete!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, prntDwnMsgs::TempBeliefMsg, logger=ConsoleLogger() )::Nothing where G <: AbstractDFG # @@ -888,7 +886,7 @@ Related Functions from Upward Inference directPriorMsgIDs, directFrtlMsgIDs, directAssignmentIDs, mcmcIterationIDs """ -function determineCliqVariableDownSequence(subfg::AbstractDFG, cliq::Graphs.ExVertex; solvable::Int=1) +function determineCliqVariableDownSequence(subfg::AbstractDFG, cliq::TreeClique; solvable::Int=1) frtl = getCliqFrontalVarIds(cliq) adj = DFG.getAdjacencyMatrix(subfg, solvable=solvable) @@ -927,7 +925,7 @@ Dev Notes - cleanup and updates required, and @spawn jl 1.3 """ function solveCliqDownFrontalProducts!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, opts::SolverParams, logger=ConsoleLogger(); MCIters::Int=3 )::Nothing where G <: AbstractDFG @@ -1009,9 +1007,9 @@ DevNotes - TODO review, are all updates atomic?? Then perhaps in-memory only can be reduced to references back to csmc.dfg. """ function buildCliqSubgraph(dfg::AbstractDFG, - treel::BayesTree, - cliq::Graphs.ExVertex, - subfg::InMemoryDFGTypes=GraphsDFG(params=getSolverParams(dfg)) ) + treel::AbstractBayesTree, + cliq::TreeClique, + subfg::InMemoryDFGTypes=InMemDFGType(params=getSolverParams(dfg)) ) # # get cliq and variable labels syms = getCliqAllVarIds(cliq) @@ -1039,9 +1037,9 @@ end # addMsgFactors!(subfg, msgs) function buildCliqSubgraph(fgl::AbstractDFG, - treel::BayesTree, + treel::AbstractBayesTree, cliqsym::Symbol, - subfg::InMemDFGType=GraphsDFG(params=getSolverParams(fgl)) ) + subfg::InMemDFGType=InMemDFGType(params=getSolverParams(fgl)) ) # buildCliqSubgraph(fgl, treel, getCliq(treel, cliqsym), subfg) end diff --git a/src/Deprecated.jl b/src/Deprecated.jl index ceceed5ce..9b5f9768c 100644 --- a/src/Deprecated.jl +++ b/src/Deprecated.jl @@ -3,12 +3,12 @@ function getShortestPathNeighbors(fgl::FactorGraph; - from::Graphs.ExVertex=nothing, - to::Graphs.ExVertex=nothing, + from::TreeClique=nothing, + to::TreeClique=nothing, neighbors::Int=0 ) edgelist = shortest_path(fgl.g, ones(num_edges(fgl.g)), from, to) - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() edgedict = edgelist2edgedict(edgelist) expandVertexList!(fgl, edgedict, vertdict) # grow verts for i in 1:neighbors @@ -19,8 +19,8 @@ function getShortestPathNeighbors(fgl::FactorGraph; end function subgraphShortestPath(fgl::FactorGraph; - from::Graphs.ExVertex=nothing, - to::Graphs.ExVertex=nothing, + from::TreeClique=nothing, + to::TreeClique=nothing, neighbors::Int=0 ) # vertdict = getShortestPathNeighbors(fgl, from=from, to=to, neighbors=neighbors) @@ -29,10 +29,10 @@ end # explore all shortest paths combinations in verts, add neighbors and reference subgraph function subGraphFromVerts(fgl::FactorGraph, - verts::Dict{Int,Graphs.ExVertex}; + verts::Dict{Int,TreeClique}; neighbors::Int=0 ) # - allverts = Dict{Int,Graphs.ExVertex}() + allverts = Dict{Int,TreeClique}() allkeys = collect(keys(verts)) len = length(allkeys) # union all shortest path combinations in a vertdict @@ -107,7 +107,7 @@ function subgraphFromVerts(fgl::FactorGraph, verts::Array{Int,1}; neighbors::Int=0 ) - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() for vert in verts vertdict[vert] = fgl.g.vertices[vert] end @@ -125,7 +125,7 @@ function subGraphFromVerts(fgl::FactorGraph, verts::T; neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}}} # - vertdict = Dict{Int,Graphs.ExVertex}() + vertdict = Dict{Int,TreeClique}() for vert in verts id = -1 vsym = Symbol(vert) @@ -143,7 +143,7 @@ end function subgraphFromVerts(fgl::FactorGraph, verts::T; - neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}, Dict{Int,Graphs.ExVertex}}} + neighbors::Int=0 ) where {T <: Union{Vector{String},Vector{Symbol}, Dict{Int,TreeClique}}} # @warn "`subgraphFromVerts` deprecated, use `subGraphFromVerts` instead." subGraphFromVerts(fgl, verts, neighbors=neighbors) @@ -159,7 +159,7 @@ end # TODO -- convert to use add_vertex! instead, since edges type must be made also function addVerticesSubgraph(fgl::FactorGraph, fgseg::FactorGraph, - vertdict::Dict{Int,Graphs.ExVertex}) + vertdict::Dict{Int,TreeClique}) for vert in vertdict fgseg.g.vertices[vert[1]] = vert[2] @@ -202,8 +202,8 @@ end Return array of all variable vertices in a clique. """ -function getCliqVars(subfg::FactorGraph, cliq::Graphs.ExVertex) - verts = Graphs.ExVertex[] +function getCliqVars(subfg::FactorGraph, cliq::TreeClique) + verts = TreeClique[] for vid in getCliqVars(subfg, cliq) push!(verts, getVert(subfg, vid, api=localapi)) end @@ -263,11 +263,11 @@ end Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -function upMsg(cliq::Graphs.ExVertex) +function upMsg(cliq::TreeClique) @warn "deprecated upMsg, use getUpMsg instead" getData(cliq).upMsg end -function upMsg(btl::BayesTree, sym::Symbol) +function upMsg(btl::AbstractBayesTree, sym::Symbol) @warn "deprecated upMsg, use getUpMsg instead" upMsg(whichCliq(btl, sym)) end @@ -277,17 +277,17 @@ end Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -function dwnMsg(cliq::Graphs.ExVertex) +function dwnMsg(cliq::TreeClique) @warn "deprecated dwnMsg, use getDwnMsgs instead" getData(cliq).dwnMsg end -function dwnMsg(btl::BayesTree, sym::Symbol) +function dwnMsg(btl::AbstractBayesTree, sym::Symbol) @warn "deprecated dwnMsg, use getDwnMsgs instead" dwnMsg(whichCliq(btl, sym)) end -function getCliquePotentials!(fg::FactorGraph, bt::BayesTree, chkcliq::Int) +function getCliquePotentials!(fg::FactorGraph, bt::AbstractBayesTree, chkcliq::Int) @error "getCliquePotentials! deprecated, use setCliqPotentials! with DFG objects instead of FactorGraph" setCliqPotentials!(fg, bt.cliques[chkcliq]) end @@ -298,7 +298,7 @@ end Pass NBPMessages back down the tree -- pre order tree traversal. """ function downMsgPassingRecursive(inp::ExploreTreeType{T}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false) where {T} - @info "====================== Clique $(inp.cliq.attributes["label"]) =============================" + @info "====================== Clique $(getLabel(inp.cliq)) =============================" mcmciter = inp.prnt != nothing ? 3 : 0; # skip mcmc in root on dwn pass rDDT = downGibbsCliqueDensity(inp.fg, inp.cliq, inp.sendmsgs, N, mcmciter, dbg) #dwnMsg @@ -322,26 +322,26 @@ end # post order tree traversal and build potential functions function upMsgPassingRecursive(inp::ExploreTreeType{T}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false) where {T} - @info "Start Clique $(inp.cliq.attributes["label"]) =============================" + @info "Start Clique $(getLabel(inp.cliq)) =============================" childMsgs = Array{NBPMessage,1}() outnei = out_neighbors(inp.cliq, inp.bt.bt) len = length(outnei) for child in outnei ett = ExploreTreeType(inp.fg, inp.bt, child, inp.cliq, NBPMessage[]) - @info "upMsgRec -- calling new recursive on $(ett.cliq.attributes["label"])" + @info "upMsgRec -- calling new recursive on $(getLabel(ett.cliq))" newmsgs = upMsgPassingRecursive( ett, N=N, dbg=dbg ) # newmsgs - @info "upMsgRec -- finished with $(ett.cliq.attributes["label"]), w $(keys(newmsgs.p)))" + @info "upMsgRec -- finished with $(getLabel(ett.cliq)), w $(keys(newmsgs.p)))" push!( childMsgs, newmsgs ) end - @info "====================== Clique $(inp.cliq.attributes["label"]) =============================" + @info "====================== Clique $(getLabel(inp.cliq)) =============================" ett = ExploreTreeType(inp.fg, inp.bt, inp.cliq, nothing, childMsgs) urt = upGibbsCliqueDensity(ett, N, dbg) # upmsgdict updateFGBT!(inp.fg, inp.bt, inp.cliq.index, urt, dbg=dbg, fillcolor="lightblue") drawpdf ? drawTree(inp.bt) : nothing - @info "End Clique $(inp.cliq.attributes["label"]) =============================" + @info "End Clique $(getLabel(inp.cliq)) =============================" urt.upMsgs end @@ -352,17 +352,17 @@ function downGibbsCliqueDensity(inp::ExploreTreeType{T}, logger=ConsoleLogger() ) where {T} # with_logger(logger) do - @info "=================== Iter Clique $(inp.cliq.attributes["label"]) ===========================" + @info "=================== Iter Clique $(getLabel(inp.cliq)) ===========================" end mcmciter = inp.prnt != nothing ? 3 : 0 return downGibbsCliqueDensity(inp.fg, inp.cliq, inp.sendmsgs, N, mcmciter, dbg) end -function prepDwnPreOrderStack!(bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}) +function prepDwnPreOrderStack!(bt::AbstractBayesTree, + parentStack::Array{TreeClique,1}) # dwn message passing function nodedata = nothing - tempStack = Array{Graphs.ExVertex,1}() + tempStack = Array{TreeClique,1}() push!(tempStack, parentStack[1]) while ( length(tempStack) != 0 || nodedata != nothing ) @@ -382,7 +382,7 @@ function prepDwnPreOrderStack!(bt::BayesTree, nothing end -function findVertsAssocCliq(fgl::FactorGraph, cliq::Graphs.ExVertex) +function findVertsAssocCliq(fgl::FactorGraph, cliq::TreeClique) cliqdata = getData(cliq) IDS = [cliqdata.frontalIDs; cliqdata.separatorIDs] #inp.cliq.attributes["frontalIDs"] @@ -392,7 +392,7 @@ function findVertsAssocCliq(fgl::FactorGraph, cliq::Graphs.ExVertex) nothing end -function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::Graphs.ExVertex, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG +function partialExploreTreeType(pfg::G, pbt::AbstractBayesTree, cliqCursor::TreeClique, prnt, pmsgs::Array{NBPMessage,1}) where G <: AbstractDFG # info("starting pett") # TODO -- expand this to grab only partial subsection from the fg and bt data structures @@ -406,8 +406,8 @@ function partialExploreTreeType(pfg::G, pbt::BayesTree, cliqCursor::Graphs.ExVer end function dispatchNewDwnProc!(fg::G, - bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, + bt::AbstractBayesTree, + parentStack::Array{TreeClique,1}, stkcnt::Int, refdict::Dict{Int,Future}; N::Int=100, @@ -428,7 +428,7 @@ function dispatchNewDwnProc!(fg::G, drawpdf ? drawTree(bt) : nothing end - emptr = BayesTree(nothing, 0, Dict{Int,Graphs.ExVertex}(), Dict{String,Int}()); + emptr = BayesTree(nothing, 0, Dict{Int,TreeClique}(), Dict{String,Int}()); for child in out_neighbors(cliq, bt.bt) # nodedata.cliq, nodedata.bt.bt haskey(refdict, child.index) ? error("dispatchNewDwnProc! -- why you already have dwnremoteref?") : nothing @@ -447,8 +447,8 @@ Notes - Simultaenously launches as many async dispatches to remote processes as there are cliques in the tree. """ function processPreOrderStack!(fg::G, - bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, + bt::AbstractBayesTree, + parentStack::Array{TreeClique,1}, refdict::Dict{Int,Future}; N::Int=100, dbg::Bool=false, @@ -478,7 +478,7 @@ function downMsgPassingIterative!(startett::ExploreTreeType{T}; drawpdf::Bool=false ) where {T} # # this is where we launch the downward iteration process from - parentStack = Array{Graphs.ExVertex,1}() + parentStack = Array{TreeClique,1}() refdict = Dict{Int,Future}() # start at the given clique in the tree -- shouldn't have to be the root. @@ -495,9 +495,9 @@ function downMsgPassingIterative!(startett::ExploreTreeType{T}; nothing end -function prepPostOrderUpPassStacks!(bt::BayesTree, - parentStack::Array{Graphs.ExVertex,1}, - childStack::Array{Graphs.ExVertex,1} ) +function prepPostOrderUpPassStacks!(bt::AbstractBayesTree, + parentStack::Array{TreeClique,1}, + childStack::Array{TreeClique,1} ) # upward message passing preparation while ( length(parentStack) != 0 ) #2.1 Pop a node from first stack and push it to second stack @@ -511,7 +511,7 @@ function prepPostOrderUpPassStacks!(bt::BayesTree, end end for child in childStack - @show child.attributes["label"] + @show getLabel(child) end nothing end @@ -519,11 +519,11 @@ end """ $SIGNATURES -Asynchronously perform up message passing, based on previoulsy prepared `chldstk::Vector{ExVertex}`. +Asynchronously perform up message passing, based on previoulsy prepared `chldstk::Vector{TreeClique}`. """ function asyncProcessPostStacks!(fgl::G, - bt::BayesTree, - chldstk::Vector{Graphs.ExVertex}, + bt::AbstractBayesTree, + chldstk::Vector{TreeClique}, stkcnt::Int, refdict::Dict{Int,Future}; N::Int=100, @@ -536,13 +536,13 @@ function asyncProcessPostStacks!(fgl::G, end cliq = chldstk[stkcnt] gomulti = true - @info "Start Clique $(cliq.attributes["label"]) =============================" + @info "Start Clique $(getLabel(cliq)) =============================" childMsgs = Array{NBPMessage,1}() ur = nothing for child in out_neighbors(cliq, bt.bt) - @info "asyncProcessPostStacks -- $(stkcnt), cliq=$(cliq.attributes["label"]), start on child $(child.attributes["label"]) haskey=$(haskey(child.attributes, "remoteref"))" + @info "asyncProcessPostStacks -- $(stkcnt), cliq=$(getLabel(cliq)), start on child $(getLabel(child)) haskey=$(haskey(child.attributes, "remoteref"))" while !haskey(refdict, child.index) - # info("Sleeping $(cliq.attributes["label"]) on lack of remoteref from $(child.attributes["label"])") + # info("Sleeping $(getLabel(cliq)) on lack of remoteref from $(getLabel(child))") # @show child.index, keys(refdict) sleep(0.25) end @@ -559,8 +559,8 @@ function asyncProcessPostStacks!(fgl::G, push!(childMsgs, ur.upMsgs) end - @info "====================== Clique $(cliq.attributes["label"]) =============================" - emptr = BayesTree(nothing, 0, Dict{Int,Graphs.ExVertex}(), Dict{String,Int}()); + @info "====================== Clique $(getLabel(cliq)) =============================" + emptr = BayesTree(nothing, 0, Dict{Int,TreeClique}(), Dict{String,Int}()); pett = partialExploreTreeType(fgl, emptr, cliq, nothing, childMsgs) # bt # parent cliq pointer is not needed here, fix Graphs.jl first if haskey(cliq.attributes, "remoteref") @@ -581,7 +581,7 @@ function asyncProcessPostStacks!(fgl::G, delete!(refdict, child.index) end - @info "End Clique $(cliq.attributes["label"]) =============================" + @info "End Clique $(getLabel(cliq)) =============================" nothing end @@ -595,8 +595,8 @@ Notes - separate multithreaded calls can occur on each separate process. """ function processPostOrderStacks!(fg::G, - bt::BayesTree, - childStack::Array{Graphs.ExVertex,1}; + bt::AbstractBayesTree, + childStack::Array{TreeClique,1}; N::Int=100, dbg::Bool=false, drawpdf::Bool=false ) where G <: AbstractDFG @@ -633,11 +633,11 @@ end Return clique pointers for the given order in which they will be solved (sequentially). """ -function getCliqOrderUpSolve(treel::BayesTree, startcliq=treel.cliques[1]) +function getCliqOrderUpSolve(treel::AbstractBayesTree, startcliq=treel.cliques[1]) # http://www.geeksforgeeks.org/iterative-postorder-traversal/ # this is where we launch the downward iteration process from - parentStack = Vector{Graphs.ExVertex}() - childStack = Vector{Graphs.ExVertex}() + parentStack = Vector{TreeClique}() + childStack = Vector{TreeClique}() #Loop while first stack is not empty push!(parentStack, startcliq) # Starting at the root means we have a top down view of the tree @@ -650,7 +650,7 @@ end Return clique pointers for the given order in which they will be solved (sequentially). """ -getTreeCliqSolveOrderUp(treel::BayesTree, startcliq=treel.cliques[1]) = getCliqOrderUpSolve(treel, startcliq) +getTreeCliqSolveOrderUp(treel::AbstractBayesTree, startcliq=treel.cliques[1]) = getCliqOrderUpSolve(treel, startcliq) """ $SIGNATURES @@ -745,7 +745,7 @@ function decodefg(fgs::FactorGraph) fgu = deepcopy(fgs) fgu.cg = nothing # will be deprecated or replaced fgu.registeredModuleFunctions = nothing # TODO: obsolete - fgu.g = Graphs.incdict(Graphs.ExVertex,is_directed=false) + fgu.g = Graphs.incdict(TreeClique,is_directed=false) @showprogress 1 "Decoding variables..." for (vsym,vid) in fgs.IDs cpvert = deepcopy(getVert(fgs, vid, api=api)) api.addvertex!(fgu, cpvert) #, labels=vnlbls) # currently losing labels @@ -756,7 +756,7 @@ function decodefg(fgs::FactorGraph) data = decodePackedType(fdata, "") # data = FunctionNodeData{ftyp}(Int[], false, false, Int[], m, gwpf) - newvert = ExVertex(fid,string(fsym)) + newvert = TreeClique(fid,string(fsym)) for (key,val) in getVert(fgs,fid,api=api).attributes newvert.attributes[key] = val end @@ -782,7 +782,7 @@ function decodefg(fgs::FactorGraph) fcnode = getVert(fgu, fsym, nt=:fnc) # ccw = solverData(fcnode) ccw_jld = deepcopy(solverData(fcnode)) - allnei = Graphs.ExVertex[] + allnei = TreeClique[] for nei in out_neighbors(fcnode, fgu.g) push!(allnei, nei) data = IncrementalInference.solverData(nei) diff --git a/src/DispatchPackedConversions.jl b/src/DispatchPackedConversions.jl index 7583c34f5..3c24e243a 100644 --- a/src/DispatchPackedConversions.jl +++ b/src/DispatchPackedConversions.jl @@ -171,7 +171,7 @@ are used for database persistence with CloudGraphs.jl. function encodefg(fgl::G ) where G <: AbstractDFG # fgs = deepcopy(fgl) - # fgs.g = Graphs.incdict(Graphs.ExVertex,is_directed=false) + # fgs.g = Graphs.incdict(TreeClique,is_directed=false) # @showprogress 1 "Encoding variables..." for vsym in getVariableIds(fgl) @@ -184,7 +184,7 @@ function encodefg(fgl::G ) where G <: AbstractDFG for (fsym,fid) in fgs.fIDs data,ftyp = convert2packedfunctionnode(fgl, fsym) data = FunctionNodeData{ftyp}(Int[], false, false, Int[], m, gwpf) - # newvert = ExVertex(fid,string(fsym)) + # newvert = TreeClique(fid,string(fsym)) # for (key,val) in getVert(fgl,fid,api=api).attributes # newvert.attributes[key] = val # end diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index 6570ca7b8..5c2b338ff 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -13,7 +13,10 @@ reshapeVec2Mat(vec::Vector, rows::Int) = reshape(vec, rows, round(Int,length(vec # still used for Bayes Tree import DistributedFactorGraphs: getData -getData(v::Graphs.ExVertex) = v.attributes["data"] +function getData(v::TreeClique) + # @warn "getData(v::TreeClique) deprecated, use getCliqueData instead" + getCliqueData(v) +end """ @@ -46,9 +49,10 @@ function setData!(f::DFGFactor, data::GenericFunctionNodeData)::Nothing return nothing end # For Bayes tree -function setData!(v::Graphs.ExVertex, data) +function setData!(v::TreeClique, data) # this is a memory gulp without replacement, old attr["data"] object is left to gc - v.attributes["data"] = data + # v.attributes["data"] = data + v.data = data nothing end @@ -659,7 +663,7 @@ Notes: - used by Bayes tree clique logic. - similar method in DFG """ -function isInitialized(vert::Graphs.ExVertex)::Bool +function isInitialized(vert::TreeClique)::Bool return solverData(vert).initialized end @@ -1115,7 +1119,7 @@ end function addConditional!(dfg::AbstractDFG, vertId::Symbol, Si::Vector{Symbol})::Nothing bnv = DFG.getVariable(dfg, vertId) - bnvd = solverData(bnv) # bnv.attributes["data"] + bnvd = solverData(bnv) bnvd.separator = Si for s in Si push!(bnvd.BayesNetOutVertIDs, s) @@ -1198,7 +1202,7 @@ function buildBayesNet!(dfg::G, push!(Si,sepNode) end end - solverData(fct).eliminated = true #fct.attributes["data"].eliminated = true + solverData(fct).eliminated = true end if typeof(solverData(fct).fnc) == CommonConvWrapper{GenericMarginal} @@ -1273,8 +1277,8 @@ function getKDE(dfg::G, lbl::Symbol) where G <: AbstractDFG end function expandEdgeListNeigh!(fgl::FactorGraph, - vertdict::Dict{Int,Graphs.ExVertex}, - edgedict::Dict{Int,Graphs.Edge{Graphs.ExVertex}}) + vertdict::Dict{Int,TreeClique}, + edgedict::Dict{Int,Graphs.Edge{TreeClique}}) #asfd for vert in vertdict for newedge in out_edges(vert[2],fgl.g) @@ -1289,8 +1293,8 @@ end # dictionary of unique vertices from edgelist function expandVertexList!(fgl::FactorGraph, - edgedict::Dict{Int,Graphs.Edge{Graphs.ExVertex}}, - vertdict::Dict{Int,Graphs.ExVertex}) + edgedict::Dict{Int,Graphs.Edge{TreeClique}}, + vertdict::Dict{Int,TreeClique}) # go through all source and target nodes for edge in edgedict @@ -1304,8 +1308,8 @@ function expandVertexList!(fgl::FactorGraph, nothing end -function edgelist2edgedict(edgelist::Array{Graphs.Edge{Graphs.ExVertex},1}) - edgedict = Dict{Int,Graphs.Edge{Graphs.ExVertex}}() +function edgelist2edgedict(edgelist::Array{Graphs.Edge{TreeClique},1}) + edgedict = Dict{Int,Graphs.Edge{TreeClique}}() for edge in edgelist edgedict[edge.index] = edge end diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index 9142e728d..38c84f514 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -294,6 +294,7 @@ export parentCliq, getParent, getCliqSiblings, + getNumCliqs, getKDE, getVertKDE, initializeNode!, @@ -507,7 +508,6 @@ export DataLayerAPI - # TODO should be deprecated const NothingUnion{T} = Union{Nothing, T} @@ -523,13 +523,13 @@ const InMemDFGType = DFG.GraphsDFG{SolverParams} # JT TODO move to somewhere mor include("BeliefTypes.jl") include("AliasScalarSampling.jl") include("DefaultNodeTypes.jl") +include("JunctionTreeTypes.jl") include("FactorGraph01.jl") include("SerializingDistributions.jl") include("DispatchPackedConversions.jl") include("FGOSUtils.jl") include("CompareUtils.jl") -include("JunctionTreeTypes.jl") include("SubGraphFunctions.jl") include("JunctionTree.jl") include("TreeBasedInitialization.jl") @@ -574,7 +574,7 @@ function __init__() * Frontal, separator, and upmessages are all drawn at different intensity of red. * Downward messages not shown, as they would just be singletons of the full separator set. """ - function spyCliqMat(cliq::Graphs.ExVertex; showmsg=true, suppressprint::Bool=false) + function spyCliqMat(cliq::TreeClique; showmsg=true, suppressprint::Bool=false) mat = deepcopy(getCliqMat(cliq, showmsg=showmsg)) # TODO -- add improved visualization here, iter vs skip mat = map(Float64, mat)*2.0.-1.0 @@ -592,12 +592,12 @@ function __init__() @show getData(cliq).directPriorMsgIDs end sp = Gadfly.spy(mat) - push!(sp.guides, Gadfly.Guide.title("$(cliq.attributes["label"]) || $(cliq.attributes["data"].frontalIDs) :$(cliq.attributes["data"].separatorIDs)")) - push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(cliq.attributes["data"].itervarIDs)")) + push!(sp.guides, Gadfly.Guide.title("$(getLabel(cliq)) || $(getData(cliq).frontalIDs) :$(getData(cliq).separatorIDs)")) + push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(getData(cliq).itervarIDs)")) push!(sp.guides, Gadfly.Guide.ylabel("lcl=$(numlcl) || msg=$(size(getCliqMsgMat(cliq),1))" )) return sp end - function spyCliqMat(bt::BayesTree, lbl::Symbol; showmsg=true, suppressprint::Bool=false) + function spyCliqMat(bt::AbstractBayesTree, lbl::Symbol; showmsg=true, suppressprint::Bool=false) spyCliqMat(whichCliq(bt,lbl), showmsg=showmsg, suppressprint=suppressprint) end end diff --git a/src/InferDimensionUtils.jl b/src/InferDimensionUtils.jl index 0501214ef..e0323bd5c 100644 --- a/src/InferDimensionUtils.jl +++ b/src/InferDimensionUtils.jl @@ -228,7 +228,7 @@ end Return the current dimensionality of solve for each variable in a clique. """ function getCliqVariableInferDims(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, saturate::Bool=true, fraction::Bool=true )::Dict{Symbol,Float64} where G <: AbstractDFG # @@ -254,7 +254,7 @@ end # getFactorSolvableDim # """ # function getCliqVarPossibleDim(dfg::G, -# cliq::Graphs.ExVertex, +# cliq::TreeClique, # saturate::Bool=true, # fraction::Bool=true )::Dict{Symbol, Float64} # # @@ -286,7 +286,7 @@ Related getCliqVariableMoreInitDims """ -function getCliqVariableInferredPercent(dfg::G, cliq::Graphs.ExVertex) where G <: AbstractDFG +function getCliqVariableInferredPercent(dfg::G, cliq::TreeClique) where G <: AbstractDFG # cliq variables factors vars = getCliqAllVarIds(cliq) @@ -321,7 +321,7 @@ Related getCliqVariableInferredPercent """ function getCliqVariableMoreInitDims(dfg::G, - cliq::Graphs.ExVertex ) where G <: AbstractDFG + cliq::TreeClique ) where G <: AbstractDFG # # cliq variables factors vars = getCliqAllVarIds(cliq) @@ -351,7 +351,7 @@ Related getVariableInferredDimFraction, getVariableDim, getVariableInferredDim, getVariablePossibleDim """ function isCliqFullDim(fg::G, - cliq::Graphs.ExVertex )::Bool where G <: AbstractDFG + cliq::TreeClique )::Bool where G <: AbstractDFG # # get various variable percentages red = getCliqVariableInferredPercent(fg, cliq) @@ -375,8 +375,8 @@ Related fetchCliqSolvableDims, getCliqVariableMoreInitDims, getSubFgPriorityInitOrder """ -function getCliqSiblingsPriorityInitOrder(tree::BayesTree, - prnt::Graphs.ExVertex, +function getCliqSiblingsPriorityInitOrder(tree::AbstractBayesTree, + prnt::TreeClique, logger=ConsoleLogger() )::Vector{Int} # sibs = getChildren(tree, prnt) diff --git a/src/JunctionTree.jl b/src/JunctionTree.jl index 590f5bd57..11ef144a7 100644 --- a/src/JunctionTree.jl +++ b/src/JunctionTree.jl @@ -6,14 +6,14 @@ export getVariableOrder Get the frontal variable IDs `::Int` for a given clique in a Bayes (Junction) tree. """ getCliqFrontalVarIds(cliqdata::Union{BayesTreeNodeData, PackedBayesTreeNodeData})::Vector{Symbol} = cliqdata.frontalIDs -getCliqFrontalVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqFrontalVarIds(getData(cliq)) +getCliqFrontalVarIds(cliq::TreeClique)::Vector{Symbol} = getCliqFrontalVarIds(getData(cliq)) """ $SIGNATURES Get the frontal variable IDs `::Int` for a given clique in a Bayes (Junction) tree. """ -getFrontals(cliqd::Union{Graphs.ExVertex,BayesTreeNodeData})::Vector{Symbol} = getCliqFrontalVarIds(cliqd) +getFrontals(cliqd::Union{TreeClique,BayesTreeNodeData})::Vector{Symbol} = getCliqFrontalVarIds(cliqd) """ @@ -21,28 +21,57 @@ getFrontals(cliqd::Union{Graphs.ExVertex,BayesTreeNodeData})::Vector{Symbol} = g Create a new clique. """ -function addClique!(bt::BayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::ExVertex where G <: AbstractDFG - bt.btid += 1 - clq = Graphs.add_vertex!(bt.bt, ExVertex(bt.btid,string("Clique",bt.btid))) - bt.cliques[bt.btid] = clq +function addClique!(bt::AbstractBayesTree, dfg::G, varID::Symbol, condIDs::Array{Symbol}=Symbol[])::TreeClique where G <: AbstractDFG + bt.btid += 1 #used by Graphs.jl for id - clq.attributes["label"] = "" + clq = TreeClique(bt.btid, string("Clique", bt.btid)) + setLabel!(clq, "") + + #TODO addClique!(bt, clq), can't we already have the parent here + if isa(bt.bt,GenericIncidenceList) + Graphs.add_vertex!(bt.bt, clq) + bt.cliques[bt.btid] = clq + elseif isa(bt.bt, MetaDiGraph) + MetaGraphs.add_vertex!(bt.bt, :clique, clq) + else + error("Oops, something went wrong") + end # Specific data container - setData!(clq, emptyBTNodeData()) - # clq.attributes["data"] = emptyBTNodeData() + # already emptyBTNodeData() in constructor + # setData!(clq, emptyBTNodeData()) appendClique!(bt, bt.btid, dfg, varID, condIDs) return clq end + +#NOTE TODO Ideas towards a standard clique interface +#TODO export +export getClique, getCliques, getCliqueIds, getCliqueData + +getClique(tree::AbstractBayesTree, cId::Int)::TreeClique = tree.cliques[cId] + +#TODO +addClique!(tree::AbstractBayesTree, parentCliqId::Int, cliq::TreeClique)::Bool = error("addClique!(tree::AbstractBayesTree, parentCliqId::Int, cliq::TreeClique) not implemented") +updateClique!(tree::AbstractBayesTree, cliq::TreeClique)::Bool = error("updateClique!(tree::AbstractBayesTree, cliq::TreeClique)::Bool not implemented") +deleteClique!(tree::AbstractBayesTree, cId::Int)::TreeClique = error("deleteClique!(tree::AbstractBayesTree, cId::Int)::TreeClique not implemented") + +getCliques(tree::AbstractBayesTree) = tree.cliques +getCliqueIds(tree::AbstractBayesTree) = keys(getCliques(tree)) + +getCliqueData(cliq::TreeClique)::BayesTreeNodeData = cliq.data +getCliqueData(tree::AbstractBayesTree, cId::Int)::BayesTreeNodeData = getClique(tree, cId) |> getCliqueData + + + """ $SIGNATURES Generate the label for particular clique (used by graphviz for visualization). """ -function makeCliqueLabel(dfg::G, bt::BayesTree, clqID::Int)::String where G <: AbstractDFG - clq = bt.cliques[clqID] +function makeCliqueLabel(dfg::G, bt::AbstractBayesTree, clqID::Int)::String where G <: AbstractDFG + clq = getClique(bt, clqID) flbl = "" clbl = "" for fr in getData(clq).frontalIDs @@ -51,7 +80,7 @@ function makeCliqueLabel(dfg::G, bt::BayesTree, clqID::Int)::String where G <: A for sepr in getData(clq).separatorIDs clbl = string(clbl, DFG.getVariable(dfg,sepr).label, ",") end - clq.attributes["label"] = string(flbl, ": ", clbl) + setLabel!(clq, string(flbl, ": ", clbl)) end """ @@ -59,8 +88,8 @@ end Add the separator for the newly created clique. """ -function appendSeparatorToClique(bt::BayesTree, clqID::Int, seprIDs::Array{Symbol,1}) - union!(getData(bt.cliques[clqID]).separatorIDs, seprIDs) +function appendSeparatorToClique(bt::AbstractBayesTree, clqID::Int, seprIDs::Array{Symbol,1}) + union!(getCliqueData(bt, clqID).separatorIDs, seprIDs) nothing end @@ -72,13 +101,13 @@ Add a new frontal variable to clique. DevNotes - TODO, define what "conditionals" are CLEARLY!! """ -function appendClique!(bt::BayesTree, +function appendClique!(bt::AbstractBayesTree, clqID::Int, dfg::AbstractDFG, varID::Symbol, seprIDs::Array{Symbol,1}=Symbol[] )::Nothing # - clq = bt.cliques[clqID] + clq = getClique(bt, clqID) var = DFG.getVariable(dfg, varID) # add frontal variable @@ -99,13 +128,24 @@ end Instantiate a new child clique in the tree. """ -function newChildClique!(bt::BayesTree, dfg::AbstractDFG, CpID::Int, varID::Symbol, Sepj::Array{Symbol,1}) +function newChildClique!(bt::AbstractBayesTree, dfg::AbstractDFG, CpID::Int, varID::Symbol, Sepj::Array{Symbol,1}) + #TODO this is too manual, replace with just addClique that takes as argument the parent + # addClique!(bt, dfg, CpID, varID, Sepj) # physically create the new clique chclq = addClique!(bt, dfg, varID, Sepj) - parent = bt.cliques[CpID] - # Staying with Graphs.jl for tree in first stage - edge = Graphs.make_edge(bt.bt, parent, chclq) - Graphs.add_edge!(bt.bt, edge) + parent = getClique(bt,CpID) + + if isa(bt.bt,GenericIncidenceList) + # Staying with Graphs.jl for tree in first stage + edge = Graphs.make_edge(bt.bt, parent, chclq) + Graphs.add_edge!(bt.bt, edge) + elseif isa(bt.bt, MetaDiGraph) + # TODO EDGE properties here + MetaGraphs.add_edge!(bt.bt, parent.index, chclq.index) + else + error("Oops, something went wrong") + end + return chclq end @@ -115,8 +155,8 @@ end Post order tree traversal and build potential functions """ -function findCliqueFromFrontal(bt::BayesTree, frtlID::Int) - for cliqPair in bt.cliques +function findCliqueFromFrontal(bt::AbstractBayesTree, frtlID::Int) + for cliqPair in getCliques(bt, cliques) id = cliqPair[1] cliq = cliqPair[2] for frtl in getFrontals(cliq) @@ -164,11 +204,11 @@ Kaess et al.: Bayes Tree, WAFR, 2010, [Alg. 2] Kaess et al.: iSAM2, IJRR, 2011, [Alg. 3] Fourie, D.: mmisam, PhD thesis, 2017. [Chpt. 5] """ -function newPotential(tree::BayesTree, dfg::G, var::Symbol, elimorder::Array{Symbol,1}) where G <: AbstractDFG +function newPotential(tree::AbstractBayesTree, dfg::G, var::Symbol, elimorder::Array{Symbol,1}) where G <: AbstractDFG firvert = DFG.getVariable(dfg,var) # no parent if (length(solverData(firvert).separator) == 0) - # if (length(tree.cliques) == 0) + # if (length(getCliques(tree)) == 0) # create new root addClique!(tree, dfg, var) # else @@ -183,7 +223,7 @@ function newPotential(tree::BayesTree, dfg::G, var::Symbol, elimorder::Array{Sym # get clique id of first eliminated frontal CpID = tree.frontals[felbl] # look to add this conditional to the tree - cliq = tree.cliques[CpID] + cliq = getClique(tree, CpID) # clique of the first eliminated frontal unFC = union(getCliqFrontalVarIds(cliq), getCliqSeparatorVarIds(cliq)) # if the separator of this new variable is identical to the (entire) clique of the firstly eliminated frontal. @@ -205,7 +245,7 @@ end Build the whole tree in batch format. """ -function buildTree!(tree::BayesTree, dfg::AbstractDFG, elimorder::Array{Symbol,1}) +function buildTree!(tree::AbstractBayesTree, dfg::AbstractDFG, elimorder::Array{Symbol,1}) revorder = reverse(elimorder,dims=1) # flipdim(p, 1), fixing #499 # prevVar = 0 for var in revorder @@ -244,7 +284,7 @@ Notes - Uses system install of graphviz.org. - Can also use Linux tool `xdot`. """ -function drawTree(treel::BayesTree; +function drawTree(treel::AbstractBayesTree; show::Bool=false, # must remain false for stability and automated use in solver filepath::String="/tmp/caesar/bt.pdf", viewerapp::String="evince", @@ -256,12 +296,12 @@ function drawTree(treel::BayesTree; # modify a deepcopy btc = deepcopy(treel) - for (cid, cliq) in btc.cliques + for (cid, cliq) in getCliques(btc) if imgs - firstlabel = split(cliq.attributes["label"],',')[1] + firstlabel = split(getLabel(cliq),',')[1] spyCliqMat(cliq, suppressprint=true) |> exportimg("/tmp/$firstlabel.png") cliq.attributes["image"] = "/tmp/$firstlabel.png" - cliq.attributes["label"] = "" + setLabel!(cliq, "") end delete!(cliq.attributes, "data") end @@ -296,11 +336,11 @@ Related: drawTree """ -function generateTexTree(treel::BayesTree; +function generateTexTree(treel::AbstractBayesTree; filepath::String="/tmp/caesar/bayes/bt") btc = deepcopy(treel) - for (cid, cliq) in btc.cliques - label = cliq.attributes["label"] + for (cid, cliq) in getCliques(btc) + label = getLabel(cliq) # Get frontals and separator, and split into elements. frt, sep = split(label,':') @@ -338,7 +378,7 @@ function generateTexTree(treel::BayesTree; newseparator = newseparator[1:end-2] # Create full label and replace the old one. newlabel = string(newfrontals, ":", newseparator) - cliq.attributes["label"] = newlabel + setLabel!(cliq, newlabel) end # Use new labels to produce `.dot` and `.tex` files. @@ -372,6 +412,7 @@ function buildTreeFromOrdering!(dfg::G, maxparallel::Int=50, solvable::Int=1 ) where G <: InMemoryDFGTypes # + t0 =time_ns() println() fge = deepcopy(dfg) @info "Building Bayes net..." @@ -391,12 +432,25 @@ function buildTreeFromOrdering!(dfg::G, end println("Find potential functions for each clique") - cliq = tree.cliques[1] # start at the root - buildCliquePotentials(dfg, tree, cliq, solvable=solvable); # fg does not have the marginals as fge does - + for cliqIds in getCliqueIds(tree) + if isRoot(tree, cliqIds) + cliq = getClique(tree, cliqIds) # start at the root + buildCliquePotentials(dfg, tree, cliq, solvable=solvable); # fg does not have the marginals as fge does + end + end + tree.buildTime = (time_ns()-t0)/1e9 return tree end +isRoot(treel::AbstractBayesTree, cliq::TreeClique) = isRoot(tree, cliq.index) + +function isRoot(treel::MetaBayesTree, cliqKey::Int) + length(MetaGraphs.inneighbors(treel.bt, cliqKey)) == 0 +end + +function isRoot(treel::BayesTree, cliqKey::Int) + length(Graphs.in_neighbors(getClique(treel, cliqKey), treel.bt)) == 0 +end """ $SIGNATURES @@ -430,7 +484,7 @@ function buildTreeFromOrdering!(dfg::DFG.AbstractDFG, end println("Find potential functions for each clique") - cliq = tree.cliques[1] # start at the root + cliq = getClique(tree, 1) # start at the root buildCliquePotentials(dfg, tree, cliq); # fg does not have the marginals as fge does return tree @@ -519,7 +573,7 @@ end Reset factor graph and build a new tree from the provided variable ordering `p`. """ -function resetBuildTreeFromOrder!(fgl::AbstractDFG, p::Vector{Symbol})::BayesTree +function resetBuildTreeFromOrder!(fgl::AbstractDFG, p::Vector{Symbol})::AbstractBayesTree resetFactorGraphNewTree!(fgl) return buildTreeFromOrdering!(fgl, p) end @@ -542,7 +596,7 @@ function wipeBuildNewTree!(dfg::G; viewerapp::String="evince", imgs::Bool=false, maxparallel::Int=50, - variableOrder::Union{Nothing, Vector{Symbol}}=nothing )::BayesTree where G <: AbstractDFG + variableOrder::Union{Nothing, Vector{Symbol}}=nothing )::AbstractBayesTree where G <: AbstractDFG # resetFactorGraphNewTree!(dfg); return prepBatchTree!(dfg, variableOrder=variableOrder, ordering=ordering, drawpdf=drawpdf, show=show, filepath=filepath, viewerapp=viewerapp, imgs=imgs, maxparallel=maxparallel); @@ -551,7 +605,7 @@ end """ $(SIGNATURES) -Return the Graphs.ExVertex node object that represents a clique in the Bayes +Return the TreeClique node object that represents a clique in the Bayes (Junction) tree, as defined by one of the frontal variables `frt<:AbstractString`. Notes @@ -561,12 +615,12 @@ Related: getCliq, getTreeAllFrontalSyms """ -getCliq(bt::BayesTree, frt::Symbol) = bt.cliques[bt.frontals[frt]] +getCliq(bt::AbstractBayesTree, frt::Symbol) = getClique(bt, bt.frontals[frt]) """ $(SIGNATURES) -Return the Graphs.ExVertex node object that represents a clique in the Bayes +Return the TreeClique node object that represents a clique in the Bayes (Junction) tree, as defined by one of the frontal variables `frt<:AbstractString`. Notes @@ -576,8 +630,8 @@ Related: getCliq, getTreeAllFrontalSyms """ -whichCliq(bt::BayesTree, frt::Symbol) = getCliq(bt, frt) -whichCliq(bt::BayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Symbol(string(frt))) +whichCliq(bt::AbstractBayesTree, frt::Symbol) = getCliq(bt, frt) +whichCliq(bt::AbstractBayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Symbol(string(frt))) """ @@ -585,7 +639,7 @@ whichCliq(bt::BayesTree, frt::T) where {T <: AbstractString} = whichCliq(bt, Sym Return boolean on whether the frontal variable `frt::Symbol` exists somewhere in the `::BayesTree`. """ -hasCliq(bt::BayesTree, frt::Symbol)::Bool = haskey(bt.frontals, frt) +hasCliq(bt::AbstractBayesTree, frt::Symbol)::Bool = haskey(bt.frontals, frt) """ $SIGNATURES @@ -603,7 +657,7 @@ function getCliqDepth(tree, cliq)::Int end return getCliqDepth(tree, prnt[1]) + 1 end -getCliqDepth(tree::BayesTree, sym::Symbol)::Int = getCliqDepth(tree, getCliq(tree, sym)) +getCliqDepth(tree::AbstractBayesTree, sym::Symbol)::Int = getCliqDepth(tree, getCliq(tree, sym)) @@ -615,12 +669,12 @@ Set the upward passing message for Bayes (Junction) tree clique `cliql`. Dev Notes - TODO setUpMsg! should also set inferred dimension """ -function setUpMsg!(cliql::ExVertex, msgs::Dict{Symbol, BallTreeDensity}) +function setUpMsg!(cliql::TreeClique, msgs::Dict{Symbol, BallTreeDensity}) @error "setUpMsg!, use inferred dimension version instead" getData(cliql).upMsg = msgs end -function setUpMsg!(cliql::ExVertex, msgs::TempBeliefMsg) #Dict{Symbol, Tuple{BallTreeDensity, Float64}} +function setUpMsg!(cliql::TreeClique, msgs::TempBeliefMsg) #Dict{Symbol, Tuple{BallTreeDensity, Float64}} # ms = Dict{Symbol, BallTreeDensity}() # for (id, val) in msgs # ms[id] = val[1] @@ -634,23 +688,23 @@ end Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -getUpMsgs(cliql::Graphs.ExVertex) = getData(cliql).upMsg -getUpMsgs(btl::BayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) +getUpMsgs(cliql::TreeClique) = getData(cliql).upMsg +getUpMsgs(btl::AbstractBayesTree, sym::Symbol) = getUpMsgs(whichCliq(btl, sym)) """ $(SIGNATURES) Return the last up message stored in `cliq` of Bayes (Junction) tree. """ -getCliqMsgsUp(cliql::Graphs.ExVertex) = upMsg(cliql) -getCliqMsgsUp(treel::BayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt)) +getCliqMsgsUp(cliql::TreeClique) = upMsg(cliql) +getCliqMsgsUp(treel::AbstractBayesTree, frt::Symbol) = getCliqMsgsUp(getCliq(treel, frt)) """ $(SIGNATURES) Set the downward passing message for Bayes (Junction) tree clique `cliql`. """ -function setDwnMsg!(cliql::ExVertex, msgs::TempBeliefMsg) #Dict{Symbol, BallTreeDensity} +function setDwnMsg!(cliql::TreeClique, msgs::TempBeliefMsg) #Dict{Symbol, BallTreeDensity} getData(cliql).dwnMsg = msgs end @@ -659,15 +713,15 @@ end Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -getDwnMsgs(cliql::Graphs.ExVertex) = getData(cliql).dwnMsg -getDwnMsgs(btl::BayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) +getDwnMsgs(cliql::TreeClique) = getData(cliql).dwnMsg +getDwnMsgs(btl::AbstractBayesTree, sym::Symbol) = getDwnMsgs(whichCliq(btl, sym)) """ $(SIGNATURES) Return the last down message stored in `cliq` of Bayes (Junction) tree. """ -getCliqMsgsDown(cliql::Graphs.ExVertex) = getDwnMsgs(cliql) +getCliqMsgsDown(cliql::TreeClique) = getDwnMsgs(cliql) function appendUseFcts!(usefcts, @@ -739,7 +793,7 @@ Dev Notes - Why not just do this, `ffcs = union( map(x->ls(fgl, x), frtl) )`? """ function getCliqFactorsFromFrontals(fgl::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, varlist::Vector{Symbol}; inseparator::Bool=true, unused::Bool=true, @@ -789,7 +843,7 @@ end Return `::Bool` on whether factor is a partial constraint. """ isPartial(fcf::T) where {T <: FunctorInferenceType} = :partial in fieldnames(T) -function isPartial(fct::DFGFactor) #fct::Graphs.ExVertex +function isPartial(fct::DFGFactor) #fct::TreeClique fcf = solverData(fct).fnc.usrfnc! isPartial(fcf) end @@ -800,8 +854,8 @@ end Determine and set the potentials for a particular `cliq` in the Bayes (Junction) tree. """ function setCliqPotentials!(dfg::G, - bt::BayesTree, - cliq::Graphs.ExVertex; + bt::AbstractBayesTree, + cliq::TreeClique; solvable::Int=1 ) where G <: AbstractDFG # varlist = getCliqVarIdsAll(cliq) @@ -830,14 +884,14 @@ function setCliqPotentials!(dfg::G, end function getCliquePotentials!(dfg::G, - bt::BayesTree, - cliq::Graphs.ExVertex ) where G <: AbstractDFG + bt::AbstractBayesTree, + cliq::TreeClique ) where G <: AbstractDFG # @warn "getCliquePotentials! deprecated, use getCliqPotentials instead." getCliqPotentials(dfg, bt, cliq) end -function cliqPotentialIDs(cliq::Graphs.ExVertex) +function cliqPotentialIDs(cliq::TreeClique) potIDs = Symbol[] for idfct in getData(cliq).potentials push!(potIDs, idfct) @@ -850,9 +904,9 @@ end Collect and returl all child clique separator variables. """ -function collectSeparators(bt::BayesTree, cliq::Graphs.ExVertex)::Vector{Symbol} +function collectSeparators(bt::AbstractBayesTree, cliq::TreeClique)::Vector{Symbol} allseps = Symbol[] - for child in out_neighbors(cliq, bt.bt)#tree + for child in childCliqs(bt, cliq)#tree allseps = [allseps; getData(child).separatorIDs] end return allseps @@ -864,7 +918,7 @@ end Return boolean matrix of factor by variable (row by column) associations within clique, corresponds to order presented by `getCliqFactorIds` and `getCliqAllVarIds`. """ -function getCliqAssocMat(cliq::Graphs.ExVertex) +function getCliqAssocMat(cliq::TreeClique) getData(cliq).cliqAssocMat end @@ -874,7 +928,7 @@ end Return boolean matrix of upward message singletons (i.e. marginal priors) from child cliques. Variable order corresponds to `getCliqAllVarIds`. """ -getCliqMsgMat(cliq::Graphs.ExVertex) = getData(cliq).cliqMsgMat +getCliqMsgMat(cliq::TreeClique) = getData(cliq).cliqMsgMat """ $SIGNATURES @@ -883,7 +937,7 @@ Return boolean matrix of factor variable associations for a clique, optionally including (`showmsg::Bool=true`) the upward message singletons. Variable order corresponds to `getCliqAllVarIds`. """ -function getCliqMat(cliq::Graphs.ExVertex; showmsg::Bool=true) +function getCliqMat(cliq::TreeClique; showmsg::Bool=true) assocMat = getCliqAssocMat(cliq) msgMat = getCliqMsgMat(cliq) mat = showmsg ? [assocMat;msgMat] : assocMat @@ -896,7 +950,7 @@ end Get `cliq` separator (a.k.a. conditional) variable ids`::Symbol`. """ getCliqSeparatorVarIds(cliqdata::Union{BayesTreeNodeData, PackedBayesTreeNodeData})::Vector{Symbol} = cliqdata.separatorIDs -getCliqSeparatorVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqSeparatorVarIds(getData(cliq)) +getCliqSeparatorVarIds(cliq::TreeClique)::Vector{Symbol} = getCliqSeparatorVarIds(getData(cliq)) """ $SIGNATURES @@ -904,7 +958,7 @@ getCliqSeparatorVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqSeparator Get `cliq` potentials (factors) ids`::Int`. """ getCliqFactorIds(cliqdata::BayesTreeNodeData)::Vector{Symbol} = cliqdata.potentials -getCliqFactorIds(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqFactorIds(getData(cliq)) +getCliqFactorIds(cliq::TreeClique)::Vector{Symbol} = getCliqFactorIds(getData(cliq)) """ $SIGNATURES @@ -915,7 +969,7 @@ Related getCliqVarIdsAll, getCliqAllFactIds, getCliqVarsWithFrontalNeighbors """ -function getCliqAllVarIds(cliq::Graphs.ExVertex)::Vector{Symbol} +function getCliqAllVarIds(cliq::TreeClique)::Vector{Symbol} frtl = getCliqFrontalVarIds(cliq) cond = getCliqSeparatorVarIds(cliq) union(frtl,cond) @@ -935,7 +989,7 @@ Related getCliqAllVarIds """ function getCliqVarsWithFrontalNeighbors(fgl::G, - cliq::Graphs.ExVertex; + cliq::TreeClique; solvable::Int=1 ) where {G <: AbstractDFG} # frtl = getCliqFrontalVarIds(cliq) @@ -961,7 +1015,7 @@ Related getCliqAllVarIds, getCliqAllFactIds """ -getCliqVarIdsAll(cliq::Graphs.ExVertex)::Vector{Symbol} = getCliqAllVarIds(cliq::Graphs.ExVertex) +getCliqVarIdsAll(cliq::TreeClique)::Vector{Symbol} = getCliqAllVarIds(cliq::TreeClique) """ $SIGNATURES @@ -975,8 +1029,8 @@ Related getCliqVarIdsAll, getCliqFactors """ getCliqFactorIdsAll(cliqd::BayesTreeNodeData) = cliqd.potentials -getCliqFactorIdsAll(cliq::Graphs.ExVertex) = getCliqFactorIdsAll(getData(cliq)) -getCliqFactorIdsAll(treel::BayesTree, frtl::Symbol) = getCliqFactorIdsAll(getCliq(treel, frtl)) +getCliqFactorIdsAll(cliq::TreeClique) = getCliqFactorIdsAll(getData(cliq)) +getCliqFactorIdsAll(treel::AbstractBayesTree, frtl::Symbol) = getCliqFactorIdsAll(getCliq(treel, frtl)) const getCliqFactors = getCliqFactorIdsAll @@ -996,7 +1050,7 @@ function getCliqAllFactIds(cliqd::BayesTreeNodeData) return getCliqFactorIdsAll(cliqd) end -function getCliqAllFactIds(cliq::Graphs.ExVertex) +function getCliqAllFactIds(cliq::TreeClique) @warn "getCliqAllFactIds deprecated, use getCliqFactorIdsAll instead." return getCliqFactorIdsAll(getData(cliq)) end @@ -1007,7 +1061,7 @@ end Get all `cliq` variable labels as `::Symbol`. """ -function getCliqAllVarSyms(dfg::G, cliq::Graphs.ExVertex)::Vector{Symbol} where G <: AbstractDFG +function getCliqAllVarSyms(dfg::G, cliq::TreeClique)::Vector{Symbol} where G <: AbstractDFG # Symbol[getSym(dfg, varid) for varid in getCliqAllVarIds(cliq)] @warn "deprecated getCliqAllVarSyms, use getCliqAllVarIds instead." getCliqAllVarIds(cliq) # not doing all frontals @@ -1021,7 +1075,7 @@ Return dictionary of down messages consisting of all frontal and separator belie Notes: - Fetches numerical results from `subdfg` as dictated in `cliq`. """ -function getCliqDownMsgsAfterDownSolve(subdfg::G, cliq::Graphs.ExVertex)::TempBeliefMsg where G <: AbstractDFG +function getCliqDownMsgsAfterDownSolve(subdfg::G, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG # Dict{Symbol, BallTreeDensity} # where the return msgs are contained container = TempBeliefMsg() # Dict{Symbol,BallTreeDensity}() @@ -1045,7 +1099,7 @@ Get variable ids`::Int` with prior factors associated with this `cliq`. Notes: - does not include any singleton messages from upward or downward message passing. """ -function getCliqVarIdsPriors(cliq::Graphs.ExVertex, +function getCliqVarIdsPriors(cliq::TreeClique, allids::Vector{Symbol}=getCliqAllVarIds(cliq), partials::Bool=true )::Vector{Symbol} # get ids with prior factors associated with this cliq @@ -1065,7 +1119,7 @@ end Return the number of factors associated with each variable in `cliq`. """ -getCliqNumAssocFactorsPerVar(cliq::Graphs.ExVertex)::Vector{Int} = sum(getCliqAssocMat(cliq), dims=1)[:] +getCliqNumAssocFactorsPerVar(cliq::TreeClique)::Vector{Int} = sum(getCliqAssocMat(cliq), dims=1)[:] @@ -1074,7 +1128,7 @@ getCliqNumAssocFactorsPerVar(cliq::Graphs.ExVertex)::Vector{Int} = sum(getCliqAs Get `cliq` variable IDs with singleton factors -- i.e. both in clique priors and up messages. """ -function getCliqVarSingletons(cliq::Graphs.ExVertex, +function getCliqVarSingletons(cliq::TreeClique, allids::Vector{Symbol}=getCliqAllVarIds(cliq), partials::Bool=true )::Vector{Symbol} # get incoming upward messages (known singletons) @@ -1094,7 +1148,7 @@ end Get each clique subgraph association matrix. """ -function compCliqAssocMatrices!(dfg::G, bt::BayesTree, cliq::Graphs.ExVertex) where G <: AbstractDFG +function compCliqAssocMatrices!(dfg::G, bt::AbstractBayesTree, cliq::TreeClique) where G <: AbstractDFG frtl = getCliqFrontalVarIds(cliq) cond = getCliqSeparatorVarIds(cliq) inmsgIDs = collectSeparators(bt, cliq) @@ -1134,9 +1188,9 @@ function compCliqAssocMatrices!(dfg::G, bt::BayesTree, cliq::Graphs.ExVertex) wh end -function countSkips(bt::BayesTree) +function countSkips(bt::AbstractBayesTree) skps = 0 - for cliq in bt.cliques + for cliq in getCliques(bt) m = getCliqMat(cliq[2]) mi = map(Int,m) skps += sum(map(Int,sum(mi, dims=1) .== 1)) @@ -1144,7 +1198,7 @@ function countSkips(bt::BayesTree) return skps end -function skipThroughMsgsIDs(cliq::Graphs.ExVertex) +function skipThroughMsgsIDs(cliq::TreeClique) cliqdata = getData(cliq) numfrtl1 = floor(Int,length(cliqdata.frontalIDs)+1) condAssocMat = cliqdata.cliqAssocMat[:,numfrtl1:end] @@ -1158,7 +1212,7 @@ function skipThroughMsgsIDs(cliq::Graphs.ExVertex) return msgidx end -function directPriorMsgIDs(cliq::Graphs.ExVertex) +function directPriorMsgIDs(cliq::TreeClique) frtl = getData(cliq).frontalIDs sepr = getData(cliq).separatorIDs cols = [frtl;sepr] @@ -1173,7 +1227,7 @@ function directPriorMsgIDs(cliq::Graphs.ExVertex) return cols[vec(collect(pmSkipCols))] end -function directFrtlMsgIDs(cliq::Graphs.ExVertex) +function directFrtlMsgIDs(cliq::TreeClique) numfrtl = length(getData(cliq).frontalIDs) frntAssocMat = getData(cliq).cliqAssocMat[:,1:numfrtl] frtlMsgMat = getData(cliq).cliqMsgMat[:,1:numfrtl] @@ -1184,7 +1238,7 @@ function directFrtlMsgIDs(cliq::Graphs.ExVertex) return getData(cliq).frontalIDs[vec(collect(mab))] end -function directAssignmentIDs(cliq::Graphs.ExVertex) +function directAssignmentIDs(cliq::TreeClique) # NOTE -- old version been included in iterated variable stack assocMat = getData(cliq).cliqAssocMat msgMat = getData(cliq).cliqMsgMat @@ -1200,7 +1254,7 @@ function directAssignmentIDs(cliq::Graphs.ExVertex) # also calculate how which are conditionals end -function mcmcIterationIDs(cliq::Graphs.ExVertex) +function mcmcIterationIDs(cliq::TreeClique) mat = getCliqMat(cliq) # assocMat = getData(cliq).cliqAssocMat # msgMat = getData(cliq).cliqMsgMat @@ -1218,7 +1272,7 @@ function mcmcIterationIDs(cliq::Graphs.ExVertex) return setdiff(usset, getData(cliq).directPriorMsgIDs) end -function getCliqMatVarIdx(cliq::Graphs.ExVertex, varid::Symbol, allids=getCliqAllVarIds(cliq) ) +function getCliqMatVarIdx(cliq::TreeClique, varid::Symbol, allids=getCliqAllVarIds(cliq) ) len = length(allids) [1:len;][allids .== varid][1] end @@ -1233,7 +1287,7 @@ Notes - least number of associated factor variables earlier in list - Same as getCliqVarSolveOrderUp """ -function mcmcIterationIdsOrdered(cliq::Graphs.ExVertex) +function mcmcIterationIdsOrdered(cliq::TreeClique) # get unordered iter list alliter = mcmcIterationIDs(cliq) @@ -1279,7 +1333,7 @@ Notes - least number of associated factor variables earlier in list - Same as mcmcIterationIdsOrdered """ -function getCliqVarSolveOrderUp(cliq::Graphs.ExVertex) +function getCliqVarSolveOrderUp(cliq::TreeClique) return mcmcIterationIdsOrdered(cliq) end @@ -1294,7 +1348,7 @@ Prepare the variable IDs for nested clique Gibbs mini-batch calculations, by ass - `directFrtlMsgIDs` """ -function setCliqMCIDs!(cliq::Graphs.ExVertex) +function setCliqMCIDs!(cliq::TreeClique) getData(cliq).directPriorMsgIDs = directPriorMsgIDs(cliq) # NOTE -- directvarIDs are combined into itervarIDs @@ -1312,11 +1366,11 @@ end # post order tree traversal and build potential functions -function buildCliquePotentials(dfg::G, bt::BayesTree, cliq::Graphs.ExVertex; solvable::Int=1) where G <: AbstractDFG - for child in out_neighbors(cliq, bt.bt)#tree +function buildCliquePotentials(dfg::G, bt::AbstractBayesTree, cliq::TreeClique; solvable::Int=1) where G <: AbstractDFG + for child in childCliqs(bt, cliq)#tree buildCliquePotentials(dfg, bt, child) end - @info "Get potentials $(cliq.attributes["label"])" + @info "Get potentials $(getLabel(cliq))" setCliqPotentials!(dfg, bt, cliq, solvable=solvable) compCliqAssocMatrices!(dfg, bt, cliq) @@ -1330,8 +1384,8 @@ end Return a vector of child cliques to `cliq`. """ -function childCliqs(treel::BayesTree, cliq::Graphs.ExVertex) - childcliqs = Vector{Graphs.ExVertex}(undef, 0) +function childCliqs(treel::BayesTree, cliq::TreeClique) + childcliqs = Vector{TreeClique}(undef, 0) for cl in Graphs.out_neighbors(cliq, treel.bt) push!(childcliqs, cl) end @@ -1341,20 +1395,29 @@ function childCliqs(treel::BayesTree, frtsym::Symbol) childCliqs(treel, whichCliq(treel, frtsym)) end + +function childCliqs(treel::MetaBayesTree, cliq::TreeClique) + childcliqs = TreeClique[] + for cIdx in MetaGraphs.outneighbors(treel.bt, cliq.index) + push!(childcliqs, get_prop(treel.bt, cIdx, :clique)) + end + return childcliqs +end + """ $(SIGNATURES) Return a vector of child cliques to `cliq`. """ -getChildren(treel::BayesTree, frtsym::Symbol) = childCliqs(treel, frtsym) -getChildren(treel::BayesTree, cliq::Graphs.ExVertex) = childCliqs(treel, cliq) +getChildren(treel::AbstractBayesTree, frtsym::Symbol) = childCliqs(treel, frtsym) +getChildren(treel::AbstractBayesTree, cliq::TreeClique) = childCliqs(treel, cliq) """ $SIGNATURES Return a vector of all siblings to a clique, which defaults to not `inclusive` the calling `cliq`. """ -function getCliqSiblings(treel::BayesTree, cliq::Graphs.ExVertex, inclusive::Bool=false)::Vector{Graphs.ExVertex} +function getCliqSiblings(treel::AbstractBayesTree, cliq::TreeClique, inclusive::Bool=false)::Vector{TreeClique} prnt = getParent(treel, cliq) if length(prnt) > 0 allch = getChildren(treel, prnt[1]) @@ -1362,7 +1425,7 @@ function getCliqSiblings(treel::BayesTree, cliq::Graphs.ExVertex, inclusive::Boo if inclusive return allch end - sibs = Graphs.ExVertex[] + sibs = TreeClique[] for ch in allch if ch.index != cliq.index push!(sibs, ch) @@ -1376,19 +1439,36 @@ end Return `cliq`'s parent clique. """ -function parentCliq(treel::BayesTree, cliq::Graphs.ExVertex) +function parentCliq(treel::BayesTree, cliq::TreeClique) Graphs.in_neighbors(cliq, treel.bt) end function parentCliq(treel::BayesTree, frtsym::Symbol) parentCliq(treel, whichCliq(treel, frtsym)) end +function parentCliq(treel::MetaBayesTree, cliq::TreeClique) + parentcliqs = TreeClique[] + for pIdx in MetaGraphs.inneighbors(treel.bt, cliq.index) + push!(parentcliqs, get_prop(treel.bt, pIdx, :clique)) + end + return parentcliqs +end + +""" + $(SIGNATURES) + +Return number of cliques in a tree. +""" +getNumCliqs(tree::BayesTree) = Graphs.num_vertices(tree.bt) +getNumCliqs(tree::MetaBayesTree) = MetaGraphs.nv(tree.bt) + + """ $(SIGNATURES) Return `cliq`'s parent clique. """ -getParent(treel::BayesTree, afrontal::Union{Symbol, Graphs.ExVertex}) = parentCliq(treel, afrontal) +getParent(treel::AbstractBayesTree, afrontal::Union{Symbol, TreeClique}) = parentCliq(treel, afrontal) """ $SIGNATURES @@ -1402,8 +1482,8 @@ Related: whichCliq, printCliqHistorySummary """ -function getTreeAllFrontalSyms(fgl::G, tree::BayesTree) where G <: AbstractDFG - cliqs = tree.cliques +function getTreeAllFrontalSyms(fgl::G, tree::AbstractBayesTree) where G <: AbstractDFG + cliqs = getCliques(tree) syms = Vector{Symbol}(undef, length(cliqs)) for (id,cliq) in cliqs syms[id] = getCliqFrontalVarIds(cliq)[1] @@ -1417,7 +1497,7 @@ end Get the `::Condition` variable for a clique, likely used for delaying state transitions in state machine solver. """ -getSolveCondition(cliq::Graphs.ExVertex) = getData(cliq).solveCondition +getSolveCondition(cliq::TreeClique) = getData(cliq).solveCondition """ @@ -1429,9 +1509,9 @@ Related getUpMsgs """ -function getTreeCliqUpMsgsAll(tree::BayesTree)::Dict{Int,TempBeliefMsg} +function getTreeCliqUpMsgsAll(tree::AbstractBayesTree)::Dict{Int,TempBeliefMsg} allUpMsgs = Dict{Int,TempBeliefMsg}() - for (idx,cliq) in tree.cliques + for (idx,cliq) in getCliques(tree) msgs = getUpMsgs(cliq) allUpMsgs[cliq.index] = TempBeliefMsg() for (lbl,msg) in msgs @@ -1457,7 +1537,7 @@ Notes inferredDim -- Information count } """ -function stackCliqUpMsgsByVariable(tree::BayesTree, +function stackCliqUpMsgsByVariable(tree::AbstractBayesTree, tmpmsgs::Dict{Int, TempBeliefMsg} )::TempUpMsgPlotting # # start of the return data structure @@ -1472,7 +1552,7 @@ function stackCliqUpMsgsByVariable(tree::BayesTree, stack[sym] = Vector{Tuple{Symbol, Int, BallTreeDensity, Float64}}() end # assemble metadata - cliq = tree.cliques[cidx] + cliq = getCliques(tree,cidx) frt = getCliqFrontalVarIds(cliq)[1] # add this belief msg and meta data to vector of variable entry push!(stack[sym], (frt, getCliqDepth(tree, cliq),msgdim[1], msgdim[2])) @@ -1487,9 +1567,9 @@ end Return the variable order stored in a tree object. """ -getVariableOrder(treel::BayesTree)::Vector{Symbol} = treel.variableOrder +getVariableOrder(treel::AbstractBayesTree)::Vector{Symbol} = treel.variableOrder -getEliminationOrder(treel::BayesTree) = treel.variableOrder +getEliminationOrder(treel::AbstractBayesTree) = treel.variableOrder """ @@ -1505,13 +1585,13 @@ Related IIF.loadTree, DFG.saveDFG, DFG.loadDFG, JLD2.@save, JLD2.@load """ -function saveTree(treel::BayesTree, +function saveTree(treel::AbstractBayesTree, filepath=joinpath("/tmp","caesar","savetree.jld2") ) # savetree = deepcopy(treel) - for i in 1:length(savetree.cliques) - if savetree.cliques[i].attributes["data"] isa BayesTreeNodeData - savetree.cliques[i].attributes["data"] = convert(PackedBayesTreeNodeData, savetree.cliques[i].attributes["data"]) + for i in 1:length(getCliques(savetree)) + if getCliqueData(savetree, i) isa BayesTreeNodeData + setData!(getClique(savetree, i), convert(PackedBayesTreeNodeData, getCliqueData(savetree, i))) end end @@ -1519,13 +1599,13 @@ function saveTree(treel::BayesTree, return filepath end -function saveTree(treeArr::Vector{BayesTree}, - filepath=joinpath("/tmp","caesar","savetrees.jld2") ) +function saveTree(treeArr::Vector{T}, + filepath=joinpath("/tmp","caesar","savetrees.jld2") ) where T <: AbstractBayesTree # savetree = deepcopy(treeArr) - for savtre in savetree, i in 1:length(savtre.cliques) - if savtre.cliques[i].attributes["data"] isa BayesTreeNodeData - savtre.cliques[i].attributes["data"] = convert(PackedBayesTreeNodeData, savtre.cliques[i].attributes["data"]) + for savtre in savetree, i in 1:length(getCliques(savtre)) + if getCliqueData(savtre, i) isa BayesTreeNodeData + setData!(getClique(savtre,i), convert(PackedBayesTreeNodeData, getCliqueData(savtre, i))) end end @@ -1551,15 +1631,15 @@ function loadTree(filepath=joinpath("/tmp","caesar","savetree.jld2")) # convert back to a type that which could not be serialized by JLD2 if savetree isa Vector - for savtre in savetree, i in 1:length(savtre.cliques) - if savtre.cliques[i].attributes["data"] isa PackedBayesTreeNodeData - savtre.cliques[i].attributes["data"] = convert(BayesTreeNodeData, savtre.cliques[i].attributes["data"]) + for savtre in savetree, i in 1:length(getCliques(savtre)) + if getCliqueData(savtre, i) isa PackedBayesTreeNodeData + setData!(getClique(savtre, i), convert(BayesTreeNodeData, getCliqueData(savtre, i))) end end else - for i in 1:length(savetree.cliques) - if savetree.cliques[i].attributes["data"] isa PackedBayesTreeNodeData - savetree.cliques[i].attributes["data"] = convert(BayesTreeNodeData, savetree.cliques[i].attributes["data"]) + for i in 1:length(getCliques(savetree)) + if getCliqueData(savetree, i) isa PackedBayesTreeNodeData + setData!(getClique(savetree, i), convert(BayesTreeNodeData, getCliqueData(savetree, i))) end end end diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index c42f086b8..87cdda464 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -1,32 +1,188 @@ +using MetaGraphs +## Cliques +""" + $(TYPEDEF) +Structure to store clique data +DEV NOTES: To replace TreeClique completely + $(FIELDS) +""" +mutable struct TreeClique + index::Int #TODO maybe depricate with Graphs.jl, or use as an unique identifier + #do not use directly as graph index as it complicates keeping the index in sync with the graph + #it may be useful with a db graph? _index + label::Symbol # this is currently a label such as clique 1, It or index may be usefull as an unique identifier such as a counter or an autogenerated GUID. + # The drawing label is saved in attributes, JT I'm not sure of the current use + data::Any#BayesTreeNodeData #FIXME There is circular type usage in TreeClique, BayesTreeNodeData, CliqStateMachineContainer https://github.com/JuliaLang/julia/issues/269 + attributes::Dict{String, Any} #The drawing attributes + #solveInProgress #on a clique level a "solve in progress" might be very handy +end + +TreeClique(i::Int, label::Symbol) = TreeClique(i, label, emptyBTNodeData(), Dict{String,Any}()) +TreeClique(i::Int, label::AbstractString) = TreeClique(i, Symbol(label)) + +Graphs.make_vertex(g::AbstractGraph{TreeClique}, label::AbstractString) = TreeClique(num_vertices(g) + 1, String(label)) +Graphs.vertex_index(v::TreeClique) = v.index +Graphs.attributes(v::TreeClique, g::AbstractGraph) = v.attributes + +#TODO the label field and label atribute is a bit confusing with accessors. +DFG.getLabel(cliq::TreeClique) = cliq.attributes["label"] +function setLabel!(cliq::TreeClique, lbl::String) + cliq.attributes["label"] = lbl + lbl +end + +## end Cliques + +## Bayes Trees + +abstract type AbstractBayesTree end -const BTGdict = GenericIncidenceList{ExVertex,Edge{ExVertex},Array{ExVertex,1},Array{Array{Edge{ExVertex},1},1}} # BayesTree declarations +const BTGdict = GenericIncidenceList{TreeClique,Edge{TreeClique},Array{TreeClique,1},Array{Array{Edge{TreeClique},1},1}} """ $(TYPEDEF) Data structure for the Bayes (Junction) tree, which is used for inference and constructed from a given `::FactorGraph`. """ -mutable struct BayesTree +mutable struct BayesTree <: AbstractBayesTree bt::BTGdict btid::Int - cliques::Dict{Int,Graphs.ExVertex} + cliques::Dict{Int,TreeClique} frontals::Dict{Symbol,Int} variableOrder::Vector{Symbol} + buildTime::Float64 end -function emptyBayesTree() - bt = BayesTree(Graphs.inclist(Graphs.ExVertex,is_directed=true), - 0, - Dict{Int,Graphs.ExVertex}(), - #[], - Dict{AbstractString, Int}(), - Symbol[] ) - return bt +BayesTree() = BayesTree(Graphs.inclist(TreeClique,is_directed=true), + 0, + Dict{Int,TreeClique}(), + Dict{AbstractString, Int}(), + Symbol[], + 0.0 ) + +#NOTE select type for development +emptyBayesTree() = BayesTree() +# emptyBayesTree() = MetaBayesTree() + +# TODO DEV MetaGraphs bayes tree, will potentially also make a LightBayesTree, CloudBayesTree, +""" +$(TYPEDEF) +Data structure for the Bayes (Junction) tree, which is used for inference and constructed from a given `::FactorGraph`. +""" +mutable struct MetaBayesTree <: AbstractBayesTree + bt::MetaDiGraph{Int,Float64} + btid::Int + # cliques::Dict{Int,TreeClique} + frontals::Dict{Symbol,Int} + variableOrder::Vector{Symbol} + buildTime::Float64 +end + +MetaBayesTree() = MetaBayesTree(MetaDiGraph{Int,Float64}(), 0, Dict{AbstractString, Int}(), Symbol[], 0.0) + +Base.propertynames(x::MetaBayesTree, private::Bool=false) = (:bt, :btid, :cliques, :frontals, :variableOrder, :buildTime) + +Base.getproperty(x::MetaBayesTree,f::Symbol) = begin + if f == :cliques + if !(@isdefined getCliquesWarnOnce) + @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" + global getCliquesWarnOnce = true + end + d = Dict{Int,Any}() + for (k,v) in x.bt.vprops + d[k] = v[:clique] + end + return d + else + getfield(x,f) + end + end + +function Base.setproperty!(x::MetaBayesTree, f::Symbol, val) + if f == :cliques + if !(@isdefined setCliquesWarnOnce) + @warn "Maybe don't use cliques field directly, TODO implement add/update/get/delete eg. getClique(tree, cliqId)" + global setCliquesWarnOnce = true + end + for (k,v) in val + set_prop!(x.bt, k, :clique, v) + end + else + setfield!(x,f,val) + end end +function MetaBayesTree(tree::BayesTree) + # create graph from Graphs.jl adjacency_matrix + mtree = MetaBayesTree(MetaDiGraph{Int, Float64}(MetaGraphs.SimpleDiGraph(Graphs.adjacency_matrix(tree.bt))), tree.btid, tree.frontals, tree.variableOrder, tree.buildTime) + + #deep copy over properties + for v in tree.bt.vertices + # set_prop!(mtree.bt, v.index, :label, deepcopy(v.label)) + set_prop!(mtree.bt, v.index, :clique, deepcopy(v)) + end + + ## TODO: placeholder for edge stored Channels + ## set message passing properties, + # for e in MetaGraphs.edges(mtree.bt) + # set_prop!(mtree.bt, e, :upMsg, Channel{BelieveMessage}(0)) + # set_prop!(mtree.bt, e, :downMsg, Channel{BelieveMessage}(0)) + # end + + return mtree + +end + +# A replacement for to_dot that saves only plotting attributes +function savedot_attributes(io::IO, g::MetaDiGraph) + write(io, "digraph G {\n") + for p in props(g) + write(io, "$(p[1])=$(p[2]);\n") + end + + for v in MetaGraphs.vertices(g) + write(io, "$v") + if length(props(g, v)) > 0 + write(io, " [ ") + end + for p in props(g, v) + # key = p[1] + # write(io, "$key=\"$(p[2])\",") + for (k,v) in p[2] + write(io, "\"$k\"=\"$v\",") + end + end + if length(props(g, v)) > 0 + write(io, "];") + end + write(io, "\n") + end + + for e in MetaGraphs.edges(g) + write(io, "$(MetaGraphs.src(e)) -> $(MetaGraphs.dst(e)) [ ") + # for p in props(g,e) + # write(io, "$(p[1])=$(p[2]), ") + # end + write(io, "]\n") + end + write(io, "}\n") +end + +function Graphs.to_dot(mdigraph::MetaDiGraph) + g = deepcopy(mdigraph) + for (i,val) in g.vprops + push!(g.vprops[i],:attributes=>val[:clique].attributes) + delete!(g.vprops[i],:clique) + end + m = PipeBuffer() + savedot_attributes(m, g) + data = take!(m) + close(m) + return String(data) +end """ $TYPEDEF @@ -37,13 +193,13 @@ TODO - remove proceed - more direct clique access (cliq, parent, children), for multi-process solves """ -mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMemoryDFGTypes} +mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMemoryDFGTypes, BT <: AbstractBayesTree} dfg::T cliqSubFg::InMemG - tree::BayesTree - cliq::Graphs.ExVertex - parentCliq::Vector{Graphs.ExVertex} - childCliqs::Vector{Graphs.ExVertex} + tree::BT + cliq::TreeClique + parentCliq::Vector{TreeClique} + childCliqs::Vector{TreeClique} forceproceed::Bool # TODO: bad flag that must be removed by refactoring sm incremental::Bool drawtree::Bool @@ -53,46 +209,46 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem refactoring::Dict{Symbol, String} oldcliqdata::BTND logger::SimpleLogger - CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, DFG.GraphsDFG, DFG.GraphsDFG}() # NOTE JT - GraphsDFG as default? - CliqStateMachineContainer{BTND}(x1::G, - x2::InMemoryDFGTypes, - x3::BayesTree, - x4::Graphs.ExVertex, - x5::Vector{Graphs.ExVertex}, - x6::Vector{Graphs.ExVertex}, - x7::Bool, - x8::Bool, - x9::Bool, - x10a::Bool, - x10aa::Bool, - x10aaa::SolverParams, - x10b::Dict{Symbol,String}=Dict{Symbol,String}(), - x11::BTND=emptyBTNodeData(), - x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} = new{BTND, G, typeof(x2)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10a,x10aa,x10aaa,x10b,x11, x13) + # CliqStateMachineContainer{BTND}() where {BTND} = new{BTND, InMemDFGType, InMemDFGType}() + # CliqStateMachineContainer{BTND}(x1::G, + # x2::InMemoryDFGTypes, + # x3::BayesTree, + # x4::TreeClique, + # x5::Vector{TreeClique}, + # x6::Vector{TreeClique}, + # x7::Bool, + # x8::Bool, + # x9::Bool, + # x10a::Bool, + # x10aa::Bool, + # x10aaa::SolverParams, + # x10b::Dict{Symbol,String}=Dict{Symbol,String}(), + # x11::BTND=emptyBTNodeData(), + # x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} = new{BTND, G, typeof(x2)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10a,x10aa,x10aaa,x10b,x11, x13) end function CliqStateMachineContainer(x1::G, x2::InMemoryDFGTypes, - x3::BayesTree, - x4::Graphs.ExVertex, - x5::Vector{Graphs.ExVertex}, - x6::Vector{Graphs.ExVertex}, + x3::AbstractBayesTree, + x4::TreeClique, + x5::Vector{TreeClique}, + x6::Vector{TreeClique}, x7::Bool, x8::Bool, x9::Bool, x10::Bool, x10aa::Bool, x10aaa::SolverParams, + x10b::Dict{Symbol,String}=Dict{Symbol,String}(), x11::BTND=emptyBTNodeData(), x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} # - CliqStateMachineContainer{BTND}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x10aa,x10aaa,Dict{Symbol,String}(),x11,x13) + CliqStateMachineContainer{BTND, G, typeof(x2), typeof(x3)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x10aa,x10aaa,x10b,x11,x13) end const CSMHistory = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}} - """ $(TYPEDEF) @@ -229,7 +385,7 @@ $(TYPEDEF) mutable struct FullExploreTreeType{T, T2, T3 <:InMemoryDFGTypes} fg::T3 bt::T2 - cliq::Graphs.ExVertex + cliq::TreeClique prnt::T sendmsgs::Vector{NBPMessage} end @@ -239,8 +395,8 @@ const ExploreTreeTypeLight{T} = FullExploreTreeType{T, Nothing} function ExploreTreeType(fgl::G, - btl::BayesTree, - vertl::Graphs.ExVertex, + btl::AbstractBayesTree, + vertl::TreeClique, prt::T, msgs::Array{NBPMessage,1} ) where {G <: AbstractDFG, T} # @@ -252,7 +408,7 @@ $(TYPEDEF) """ mutable struct MsgPassType fg::GraphsDFG - cliq::Graphs.ExVertex + cliq::TreeClique vid::Symbol # Int msgs::Array{NBPMessage,1} N::Int diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 12ff92bba..977be8185 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -64,7 +64,7 @@ Add all potentials associated with this clique and vertid to dens. function packFromLocalPotentials!(dfg::AbstractDFG, dens::Vector{BallTreeDensity}, wfac::Vector{Symbol}, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, N::Int, dbg::Bool=false )::Float64 @@ -90,7 +90,7 @@ end function packFromLocalPartials!(fgl::G, partials::Dict{Int, Vector{BallTreeDensity}}, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, N::Int, dbg::Bool=false ) where G <: AbstractDFG @@ -428,7 +428,7 @@ trasit integral -- here involving separate approximate functional convolution an product operations. """ function cliqGibbs(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, vsym::Symbol, inmsgs::Array{NBPMessage,1}, N::Int, @@ -485,7 +485,7 @@ end function doFMCIteration(fgl::AbstractDFG, vsym::Symbol, - cliq::Graphs.ExVertex, + cliq::TreeClique, fmsgs, N::Int, dbg::Bool, @@ -516,7 +516,7 @@ of the stipulated proposal convolutions and products of the functional objects for tree clique `cliq`. """ function fmcmc!(fgl::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, fmsgs::Vector{NBPMessage}, lbls::Vector{Symbol}, N::Int, @@ -526,7 +526,7 @@ function fmcmc!(fgl::G, multithreaded::Bool=false ) where G <: AbstractDFG # with_logger(logger) do - @info "---------- successive fnc approx ------------$(cliq.attributes["label"])" + @info "---------- successive fnc approx ------------$(getLabel(cliq))" end # repeat several iterations of functional Gibbs sampling for fixed point convergence if length(lbls) == 1 @@ -575,7 +575,7 @@ Calculate a fresh (single step) approximation to the variable `sym` in clique `c Which clique to be used is defined by frontal variable symbols (`cliq` in this case) -- see `whichCliq(...)` for more details. The `sym` symbol indicates which symbol of this clique to be calculated. **Note** that the `sym` variable must appear in the clique where `cliq` is a frontal variable. """ function treeProductUp(fg::AbstractDFG, - tree::BayesTree, + tree::AbstractBayesTree, cliq::Symbol, sym::Symbol; N::Int=100, @@ -617,7 +617,7 @@ Calculate a fresh---single step---approximation to the variable `sym` in clique Which clique to be used is defined by frontal variable symbols (`cliq` in this case) -- see `whichCliq(...)` for more details. The `sym` symbol indicates which symbol of this clique to be calculated. **Note** that the `sym` variable must appear in the clique where `cliq` is a frontal variable. """ function treeProductDwn(fg::G, - tree::BayesTree, + tree::AbstractBayesTree, cliq::Symbol, sym::Symbol; N::Int=100, @@ -741,13 +741,13 @@ end function dwnPrepOutMsg(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::Array{NBPMessage,1}, d::Dict{Symbol, T}, logger=ConsoleLogger()) where {G <: AbstractDFG, T} # pack all downcoming conditionals in a dictionary too. with_logger(logger) do - if cliq.index != 1 + if cliq.index != 1 #TODO there may be more than one root @info "Dwn msg keys $(keys(dwnMsgs[1].p))" @info "fg vars $(ls(fg))" end # ignore root, now incoming dwn msg @@ -774,7 +774,7 @@ Notes - Only update frontal variables of the clique. """ function downGibbsCliqueDensity(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::Array{NBPMessage,1}, N::Int=100, MCMCIter::Int=3, @@ -824,7 +824,7 @@ function downGibbsCliqueDensity(fg::G, return DownReturnBPType(m, mdbg, d, dwnkeepmsgs) end function downGibbsCliqueDensity(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwnMsgs::TempBeliefMsg, # Dict{Symbol,BallTreeDensity}, N::Int=100, MCMCIter::Int=3, @@ -854,7 +854,7 @@ end Set the color of a cliq in the Bayes (Junction) tree. """ -function setCliqDrawColor(cliq::Graphs.ExVertex, fillcolor::String)::Nothing +function setCliqDrawColor(cliq::TreeClique, fillcolor::String)::Nothing cliq.attributes["fillcolor"] = fillcolor cliq.attributes["style"] = "filled" nothing @@ -866,14 +866,14 @@ end Update cliq `cliqID` in Bayes (Juction) tree `bt` according to contents of `ddt` -- intended use is to update main clique after a downward belief propagation computation has been completed per clique. """ function updateFGBT!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliqID::Int, drt::DownReturnBPType; dbg::Bool=false, fillcolor::String="", logger=ConsoleLogger() ) where G <: AbstractDFG # - cliq = bt.cliques[cliqID] + cliq = getClique(bt, cliqID) # if dbg # cliq.attributes["debugDwn"] = deepcopy(drt.dbgDwn) # end @@ -902,7 +902,7 @@ end Update cliq `cliqID` in Bayes (Juction) tree `bt` according to contents of `urt` -- intended use is to update main clique after a upward belief propagation computation has been completed per clique. """ function updateFGBT!(fg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, urt::UpReturnBPType; dbg::Bool=false, fillcolor::String="", @@ -926,19 +926,18 @@ function updateFGBT!(fg::G, setValKDE!(updvert, deepcopy(dat), true) ## TODO -- not sure if deepcopy is required end with_logger(logger) do - @info "updateFGBT! up -- updated $(cliq.attributes["label"])" + @info "updateFGBT! up -- updated $(getLabel(cliq))" end nothing end function updateFGBT!(fg::G, - bt::BayesTree, + bt::AbstractBayesTree, cliqID::Int, urt::UpReturnBPType; dbg::Bool=false, fillcolor::String="" ) where G <: AbstractDFG # - cliq = bt.cliques[cliqID] - cliq = bt.cliques[cliqID] + cliq = getClique(bt, cliqID) updateFGBT!( fg, cliq, urt, dbg=dbg, fillcolor=fillcolor ) end @@ -946,14 +945,14 @@ end """ $SIGNATURES -Get and return upward belief messages as stored in child cliques from `treel::BayesTree`. +Get and return upward belief messages as stored in child cliques from `treel::AbstractBayesTree`. Notes - Use last parameter to select the return format. """ function getCliqChildMsgsUp(fg_::G, - treel::BayesTree, - cliq::Graphs.ExVertex, + treel::AbstractBayesTree, + cliq::TreeClique, ::Type{EasyMessage} ) where G <: AbstractDFG # childmsgs = NBPMessage[] @@ -969,7 +968,7 @@ function getCliqChildMsgsUp(fg_::G, return childmsgs end -function getCliqChildMsgsUp(treel::BayesTree, cliq::Graphs.ExVertex, ::Type{BallTreeDensity}) +function getCliqChildMsgsUp(treel::AbstractBayesTree, cliq::TreeClique, ::Type{BallTreeDensity}) childmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity,Float64}}}() # Vector{Bool} for child in getChildren(treel, cliq) for (key, bel) in getUpMsgs(child) @@ -993,7 +992,7 @@ Notes - Different from down initialization messages that do calculate new values -- see `prepCliqInitMsgsDown!`. - Basically converts function `getDwnMsgs` from `Dict{Symbol,BallTreeDensity}` to `Dict{Symbol,Vector{BallTreeDensity}}`. """ -function getCliqParentMsgDown(treel::BayesTree, cliq::Graphs.ExVertex) +function getCliqParentMsgDown(treel::AbstractBayesTree, cliq::TreeClique) downmsgs = Dict{Symbol,Vector{Tuple{BallTreeDensity, Float64}}}() for prnt in getParent(treel, cliq) for (key, bel) in getDwnMsgs(prnt) @@ -1021,7 +1020,7 @@ Future - TODO: internal function chain is too long and needs to be refactored for maintainability. """ function approxCliqMarginalUp!(fgl::G, - treel::BayesTree, + treel::AbstractBayesTree, csym::Symbol, onduplicate=true; N::Int=100, @@ -1039,10 +1038,10 @@ function approxCliqMarginalUp!(fgl::G, tree_ = onduplicate ? wipeBuildNewTree!(fgl) : treel - # copy up and down msgs that may already exists + # copy up and down msgs that may already exists #TODO Exists where? it copies from tree_ to tree if onduplicate for (id, cliq) in tree_.cliques - setUpMsg!(tree_.cliques[cliq.index], getUpMsgs(cliq)) + setUpMsg!(tree_.cliques[cliq.index], getUpMsgs(cliq)) #TODO cliq.index may be problematic, how do we know it will be the same index on rebuilding? setDwnMsg!(tree_.cliques[cliq.index], getDwnMsgs(cliq)) end end @@ -1056,7 +1055,7 @@ function approxCliqMarginalUp!(fgl::G, # TODO use subgraph copy of factor graph for operations and transfer frontal variables only with_logger(logger) do - @info "=== start Clique $(cliq.attributes["label"]) ======================" + @info "=== start Clique $(getLabel(cliq)) ======================" end ett = FullExploreTreeType(fg_, nothing, cliq, nothing, childmsgs) urt = UpReturnBPType() @@ -1093,7 +1092,7 @@ function approxCliqMarginalUp!(fgl::G, drawpdf ? drawTree(tree_) : nothing with_logger(logger) do - @info "=== end Clique $(cliq.attributes["label"]) ========================" + @info "=== end Clique $(getLabel(cliq)) ========================" end return urt end @@ -1108,7 +1107,7 @@ Notes - `onduplicate=true` by default internally uses deepcopy of factor graph and Bayes tree, and does **not** update the given objects. Set false to update `fgl` and `treel` during compute. """ function doCliqInferenceUp!(fgl::FactorGraph, - treel::BayesTree, + treel::AbstractBayesTree, csym::Symbol, onduplicate=true; N::Int=100, @@ -1132,8 +1131,8 @@ end # * Can adjust the number of `iters::Int=3` must be performed on the `itervars` of this clique. # """ # function doCliqInferenceUp!(fgl::FactorGraph, -# treel::BayesTree, -# cliql::Graphs.ExVertex; +# treel::AbstractBayesTree, +# cliql::TreeClique; # N::Int=100, # dbg::Bool=false, # iters::Int=3 ) @@ -1172,8 +1171,8 @@ end Set all up `upsolved` and `downsolved` cliq data flags `to::Bool=false`. """ -function setAllSolveFlags!(treel::BayesTree, to::Bool=false)::Nothing - for (id, cliq) in treel.cliques +function setAllSolveFlags!(treel::AbstractBayesTree, to::Bool=false)::Nothing + for (id, cliq) in getCliques(treel) cliqdata = getData(cliq) cliqdata.initialized = :null cliqdata.upsolved = to @@ -1187,10 +1186,10 @@ end Return true or false depending on whether the tree has been fully initialized/solved/marginalized. """ -function isTreeSolved(treel::BayesTree; skipinitialized::Bool=false)::Bool +function isTreeSolved(treel::AbstractBayesTree; skipinitialized::Bool=false)::Bool acclist = Symbol[:upsolved; :downsolved; :marginalized] skipinitialized ? nothing : push!(acclist, :initialized) - for (clid, cliq) in treel.cliques + for (clid, cliq) in getCliques(treel) if !(getCliqStatus(cliq) in acclist) return false end @@ -1198,8 +1197,8 @@ function isTreeSolved(treel::BayesTree; skipinitialized::Bool=false)::Bool return true end -function isTreeSolvedUp(treel::BayesTree)::Bool - for (clid, cliq) in treel.cliques +function isTreeSolvedUp(treel::AbstractBayesTree)::Bool + for (clid, cliq) in getCliques(treel) if getCliqStatus(cliq) != :upsolved return false end @@ -1213,7 +1212,7 @@ end Return `::Bool` on whether all variables in this `cliq` are marginalzed. """ -function isCliqMarginalizedFromVars(subfg::FactorGraph, cliq::Graphs.ExVertex) +function isCliqMarginalizedFromVars(subfg::FactorGraph, cliq::TreeClique) for vert in getCliqVars(subfg, cliq) if !isMarginalized(vert) return false @@ -1227,7 +1226,7 @@ end Set the marginalized status of a clique. """ -function setCliqAsMarginalized!(cliq::Graphs.ExVertex, status::Bool) +function setCliqAsMarginalized!(cliq::TreeClique, status::Bool) if status getData(cliq).initialized = :marginalized else @@ -1248,8 +1247,8 @@ Run through entire tree and set cliques as marginalized if all clique variables Notes: - TODO can be made fully parallel, consider converting for use with `@threads` `for`. """ -function updateTreeCliquesAsMarginalizedFromVars!(fgl::FactorGraph, tree::BayesTree)::Nothing - for (clid, cliq) in tree.cliques +function updateTreeCliquesAsMarginalizedFromVars!(fgl::FactorGraph, tree::AbstractBayesTree)::Nothing + for (clid, cliq) in getCliques(tree) if isCliqMarginalizedFromVars(fgl, cliq) setCliqAsMarginalized!(cliq, true) end @@ -1266,9 +1265,9 @@ Notes - Will change previous clique status from `:downsolved` to `:initialized` only. - Sets the color of tree clique to `lightgreen`. """ -function resetTreeCliquesForUpSolve!(treel::BayesTree)::Nothing +function resetTreeCliquesForUpSolve!(treel::AbstractBayesTree)::Nothing acclist = Symbol[:downsolved;] - for (clid, cliq) in treel.cliques + for (clid, cliq) in getCliques(treel) if getCliqStatus(cliq) in acclist setCliqStatus!(cliq, :initialized) setCliqDrawColor(cliq, "sienna") @@ -1280,17 +1279,17 @@ end """ $SIGNATURES -Special internal function to try return the clique data if succesfully identified in `othertree::BayesTree`, +Special internal function to try return the clique data if succesfully identified in `othertree::AbstractBayesTree`, based on contents of `seeksSimilar::BayesTreeNodeData`. Notes - Used to identify and skip similar cliques (i.e. recycle computations) """ -function attemptTreeSimilarClique(othertree::BayesTree, seeksSimilar::BayesTreeNodeData)::Graphs.ExVertex +function attemptTreeSimilarClique(othertree::AbstractBayesTree, seeksSimilar::BayesTreeNodeData)::TreeClique # inner convenience function for returning empty clique function EMPTYCLIQ() - clq = ExVertex(-1,"null") - clq.attributes["label"] = "" + clq = TreeClique(-1,"null") + setLabel!(clq, "") setData!(clq, emptyBTNodeData()) return clq end @@ -1332,11 +1331,11 @@ end function tryCliqStateMachineSolve!(dfg::G, - treel::BayesTree, + treel::AbstractBayesTree, i::Int; # cliqHistories; N::Int=100, - oldtree::BayesTree=emptyBayesTree(), + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, limititers::Int=-1, downsolve::Bool=false, @@ -1345,7 +1344,7 @@ function tryCliqStateMachineSolve!(dfg::G, recordcliqs::Vector{Symbol}=Symbol[]) where G <: AbstractDFG # clst = :na - cliq = treel.cliques[i] + cliq = getClique(treel, i) syms = getCliqFrontalVarIds(cliq) # ids = oldcliq = attemptTreeSimilarClique(oldtree, getData(cliq)) oldcliqdata = getData(oldcliq) @@ -1408,14 +1407,14 @@ end After solving, clique histories can be inserted back into the tree for later reference. This function helps do the required assigment task. """ -function assignTreeHistory!(treel::BayesTree, cliqHistories::Dict) - for i in 1:length(treel.cliques) +function assignTreeHistory!(treel::AbstractBayesTree, cliqHistories::Dict) + for i in 1:length(getCliques(treel)) if haskey(cliqHistories, i) hist = cliqHistories[i] for i in 1:length(hist) hist[i][4].logger = SimpleLogger(stdout) end - getData(treel.cliques[i]).statehistory=hist + getCliqueData(treel, i).statehistory=hist end end end @@ -1435,7 +1434,7 @@ function fetchCliqTaskHistoryAll!(smt, hist) end end -function fetchAssignTaskHistoryAll!(tree::BayesTree, smt) +function fetchAssignTaskHistoryAll!(tree::AbstractBayesTree, smt) hist = Dict{Int, Vector{Tuple{DateTime,Int,Function,CliqStateMachineContainer}}}() fetchCliqTaskHistoryAll!(smt, hist) assignTreeHistory!(tree, hist) @@ -1456,8 +1455,8 @@ Related initInferTreeUp! """ function asyncTreeInferUp!(dfg::G, - treel::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + treel::AbstractBayesTree; + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, limititers::Int=-1, @@ -1475,13 +1474,13 @@ function asyncTreeInferUp!(dfg::G, end # queue all the tasks - alltasks = Vector{Task}(undef, length(treel.cliques)) + alltasks = Vector{Task}(undef, length(getCliques(treel))) # cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}() if !isTreeSolved(treel, skipinitialized=true) # @sync begin # duplicate int i into async (important for concurrency) - for i in 1:length(treel.cliques) - scsym = getCliqFrontalVarIds(treel.cliques[i]) + for i in 1:length(getCliques(treel)) + scsym = getCliqFrontalVarIds(getClique(treel, i)) if length(intersect(scsym, skipcliqids)) == 0 alltasks[i] = @async tryCliqStateMachineSolve!(dfg, treel, i, oldtree=oldtree, drawtree=drawtree, limititers=limititers, downsolve=downsolve, delaycliqs=delaycliqs, recordcliqs=recordcliqs, incremental=incremental, N=N) end # if @@ -1492,9 +1491,9 @@ function asyncTreeInferUp!(dfg::G, # post-hoc store possible state machine history in clique (without recursively saving earlier history inside state history) # assignTreeHistory!(treel, cliqHistories) - # for i in 1:length(treel.cliques) + # for i in 1:length(getCliques(treel)) # if haskey(cliqHistories, i) - # getData(treel.cliques[i]).statehistory=cliqHistories[i] + # getCliqueData(treel, i).statehistory=cliqHistories[i] # end # end @@ -1513,8 +1512,8 @@ Related asyncTreeInferUp! """ function initInferTreeUp!(dfg::G, - treel::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + treel::AbstractBayesTree; + oldtree::AbstractBayesTree=emptyBayesTree(), drawtree::Bool=false, N::Int=100, limititers::Int=-1, @@ -1530,13 +1529,13 @@ function initInferTreeUp!(dfg::G, drawtree ? drawTree(treel, show=false, filepath=joinpath(getSolverParams(dfg).logpath,"bt.pdf")) : nothing # queue all the tasks - alltasks = Vector{Task}(undef, length(treel.cliques)) + alltasks = Vector{Task}(undef, length(getCliques(treel))) cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}() if !isTreeSolved(treel, skipinitialized=true) @sync begin # duplicate int i into async (important for concurrency) - for i in 1:length(treel.cliques) - scsym = getCliqFrontalVarIds(treel.cliques[i]) + for i in 1:length(getCliques(treel)) + scsym = getCliqFrontalVarIds(getClique(treel, i)) if length(intersect(scsym, skipcliqids)) == 0 alltasks[i] = @async tryCliqStateMachineSolve!(dfg, treel, i, oldtree=oldtree, drawtree=drawtree, limititers=limititers, downsolve=downsolve, incremental=incremental, delaycliqs=delaycliqs, recordcliqs=recordcliqs, N=N) end # if @@ -1548,13 +1547,13 @@ function initInferTreeUp!(dfg::G, # post-hoc store possible state machine history in clique (without recursively saving earlier history inside state history) assignTreeHistory!(treel, cliqHistories) - # for i in 1:length(treel.cliques) + # for i in 1:length(getCliques(treel)) # if haskey(cliqHistories, i) # hist = cliqHistories[i] # for i in 1:length(hist) # hist[i][4].logger = ConsoleLogger() # end - # getData(treel.cliques[i]).statehistory=hist + # getCliqueData(treel,i).statehistory=hist # end # end diff --git a/src/SolverAPI.jl b/src/SolverAPI.jl index ce861a9be..65c24a1b5 100644 --- a/src/SolverAPI.jl +++ b/src/SolverAPI.jl @@ -21,7 +21,7 @@ Related solveCliq!, wipeBuildNewTree! """ function solveTree!(dfgl::G, - oldtree::BayesTree=emptyBayesTree(); + oldtree::AbstractBayesTree=emptyBayesTree(); delaycliqs::Vector{Symbol}=Symbol[], recordcliqs::Vector{Symbol}=Symbol[], skipcliqids::Vector{Symbol}=Symbol[], @@ -53,8 +53,10 @@ function solveTree!(dfgl::G, # transfer new tree to outside parameter oldtree.bt = tree.bt oldtree.btid = tree.btid - oldtree.cliques = tree.cliques + oldtree.cliques = tree.cliques #TODO JT kyk meer detail, this is a bit strange as its a copy of data in graph oldtree.frontals = tree.frontals + oldtree.variableOrder = tree.variableOrder + oldtree.buildTime = tree.buildTime return oldtree, smtasks, hist end @@ -76,7 +78,7 @@ Related solveTree!, wipeBuildNewTree! """ function solveCliq!(dfgl::G, - tree::BayesTree, + tree::AbstractBayesTree, cliqid::Symbol; recordcliq::Bool=false, # cliqHistories = Dict{Int,Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}}}(), @@ -114,8 +116,8 @@ Notes - For legacy versions of tree traversal, see `inferOverTreeIterative!` instead. """ function inferOverTree!(dfg::G, - bt::BayesTree; - oldtree::BayesTree=emptyBayesTree(), + bt::AbstractBayesTree; + oldtree::AbstractBayesTree=emptyBayesTree(), N::Int=100, upsolve::Bool=true, downsolve::Bool=true, @@ -155,7 +157,7 @@ Notes - Even older code is available as `inferOverTreeR!` """ function inferOverTreeIterative!(dfg::G, - bt::BayesTree; + bt::AbstractBayesTree; N::Int=100, dbg::Bool=false, drawpdf::Bool=false ) where G <: AbstractDFG @@ -165,9 +167,9 @@ function inferOverTreeIterative!(dfg::G, @info "Ensure all nodes are initialized" ensureAllInitialized!(dfg) @info "Do multi-process upward pass of inference on tree" - upMsgPassingIterative!(ExploreTreeType(dfg, bt, bt.cliques[1], nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); + upMsgPassingIterative!(ExploreTreeType(dfg, bt, getClique(bt, 1), nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); @info "Do multi-process downward pass of inference on tree" - downMsgPassingIterative!(ExploreTreeType(dfg, bt, bt.cliques[1], nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); + downMsgPassingIterative!(ExploreTreeType(dfg, bt, getClique(bt, 1), nothing, NBPMessage[]),N=N, dbg=dbg, drawpdf=drawpdf); return smtasks, ch end @@ -177,7 +179,7 @@ end Perform up and down message passing (single process, recursive) algorithm for full sum-product solution of all continuous marginal beliefs. """ function inferOverTreeR!(fgl::G, - bt::BayesTree; + bt::AbstractBayesTree; N::Int=100, dbg::Bool=false, drawpdf::Bool=false, @@ -193,10 +195,10 @@ function inferOverTreeR!(fgl::G, else @info "Do conventional recursive up inference over tree" ensureAllInitialized!(fgl) - upMsgPassingRecursive(ExploreTreeType(fgl, bt, bt.cliques[1], nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); + upMsgPassingRecursive(ExploreTreeType(fgl, bt, getClique(bt, 1), nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); end @info "Do recursive down inference over tree" - downMsgPassingRecursive(ExploreTreeType(fgl, bt, bt.cliques[1], nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); + downMsgPassingRecursive(ExploreTreeType(fgl, bt, getClique(bt, 1), nothing, NBPMessage[]), N=N, dbg=dbg, drawpdf=drawpdf); return smtasks, ch end @@ -210,7 +212,7 @@ end Perform multimodal incremental smoothing and mapping (mm-iSAM) computations over given factor graph `fgl::FactorGraph` on the local computer. A pdf of the Bayes (Junction) tree will be generated in the working folder with `drawpdf=true` """ function batchSolve!(dfg::G, - oldtree::BayesTree=emptyBayesTree(); + oldtree::AbstractBayesTree=emptyBayesTree(); upsolve::Bool=true, downsolve::Bool=true, drawpdf::Bool=false, diff --git a/src/SolverUtilities.jl b/src/SolverUtilities.jl index 7a5fb8860..f4f30d47f 100644 --- a/src/SolverUtilities.jl +++ b/src/SolverUtilities.jl @@ -237,8 +237,8 @@ Dev Notes - TODO not all kde manifolds will initialize to zero. """ function resetCliqSolve!(dfg::G, - treel::BayesTree, - cliq::Graphs.ExVertex; + treel::AbstractBayesTree, + cliq::TreeClique; solveKey::Symbol=:default)::Nothing where G <: AbstractDFG # cda = getData(cliq) @@ -260,7 +260,7 @@ function resetCliqSolve!(dfg::G, end function resetCliqSolve!(dfg::G, - treel::BayesTree, + treel::AbstractBayesTree, frt::Symbol; solveKey::Symbol=:default )::Nothing where G <: AbstractDFG # diff --git a/src/SubGraphFunctions.jl b/src/SubGraphFunctions.jl index 93d878077..0cbb94501 100644 --- a/src/SubGraphFunctions.jl +++ b/src/SubGraphFunctions.jl @@ -44,7 +44,7 @@ Notes - `varsym::Symbol` defaults to the cliq frontal variable definition but can in case a separator variable is required instead. """ -function buildCliqSubgraphDown(fgl::AbstractDFG, treel::BayesTree, cliqsym::Symbol, varsym::Symbol=cliqsym) +function buildCliqSubgraphDown(fgl::AbstractDFG, treel::AbstractBayesTree, cliqsym::Symbol, varsym::Symbol=cliqsym) @warn "Obsolete, buildCliqSubGraph*() is no longer in use" # build a subgraph copy of clique cliq = whichCliq(treel, cliqsym) diff --git a/src/TreeBasedInitialization.jl b/src/TreeBasedInitialization.jl index a84a62f8a..4e419ef04 100644 --- a/src/TreeBasedInitialization.jl +++ b/src/TreeBasedInitialization.jl @@ -4,9 +4,9 @@ Based on a push model from child cliques that should have already completed their computation. """ -getCliqInitUpMsgs(cliq::Graphs.ExVertex)::Dict{Int, TempBeliefMsg} = getData(cliq).upInitMsgs +getCliqInitUpMsgs(cliq::TreeClique)::Dict{Int, TempBeliefMsg} = getData(cliq).upInitMsgs -function setCliqUpInitMsgs!(cliq::Graphs.ExVertex, childid::Int, msg::TempBeliefMsg) +function setCliqUpInitMsgs!(cliq::TreeClique, childid::Int, msg::TempBeliefMsg) cd = getData(cliq) soco = getSolveCondition(cliq) lockUpStatus!(cd) @@ -20,11 +20,11 @@ function setCliqUpInitMsgs!(cliq::Graphs.ExVertex, childid::Int, msg::TempBelief nothing end -function isCliqInitialized(cliq::Graphs.ExVertex)::Bool +function isCliqInitialized(cliq::TreeClique)::Bool return getData(cliq).initialized in [:initialized; :upsolved] end -function isCliqUpSolved(cliq::Graphs.ExVertex)::Bool +function isCliqUpSolved(cliq::TreeClique)::Bool return getData(cliq).initialized == :upsolved end @@ -39,7 +39,7 @@ sequence). Notes: - sorts id for increasing number of connected factors. """ -function getCliqVarInitOrderUp(cliq::Graphs.ExVertex) +function getCliqVarInitOrderUp(cliq::TreeClique) # rules to explore dimension from one to the other? # get all variable ids and number of associated factors @@ -82,9 +82,9 @@ function getCliqVarInitOrderUp(cliq::Graphs.ExVertex) end lockUpStatus!(cdat::BayesTreeNodeData, idx::Int=1) = put!(cdat.lockUpStatus, idx) -lockUpStatus!(cliq::Graphs.ExVertex, idx::Int=1) = lockUpStatus!(getData(cliq), idx) +lockUpStatus!(cliq::TreeClique, idx::Int=1) = lockUpStatus!(getData(cliq), idx) unlockUpStatus!(cdat::BayesTreeNodeData) = take!(cdat.lockUpStatus) -unlockUpStatus!(cliq::Graphs.ExVertex) = unlockUpStatus!(getData(cliq)) +unlockUpStatus!(cliq::TreeClique) = unlockUpStatus!(getData(cliq)) function lockDwnStatus!(cdat::BayesTreeNodeData, idx::Int=1; logger=ConsoleLogger()) with_logger(logger) do @@ -118,7 +118,7 @@ Notes Dev Notes - Should be made an atomic transaction """ -function notifyCliqUpInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=ConsoleLogger()) +function notifyCliqUpInitStatus!(cliq::TreeClique, status::Symbol; logger=ConsoleLogger()) cd = getData(cliq) with_logger(logger) do tt = split(string(now()), 'T')[end] @@ -152,7 +152,7 @@ function notifyCliqUpInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=C nothing end -function notifyCliqDownInitStatus!(cliq::Graphs.ExVertex, status::Symbol; logger=ConsoleLogger()) +function notifyCliqDownInitStatus!(cliq::TreeClique, status::Symbol; logger=ConsoleLogger()) cdat = getData(cliq) with_logger(logger) do @info "$(now()) $(current_task()), cliq=$(cliq.index), notifyCliqDownInitStatus! -- pre-lock, new $(cdat.initialized)-->$(status)" @@ -191,9 +191,9 @@ end Return true if clique has completed the local upward direction inference procedure. """ -isUpInferenceComplete(cliq::Graphs.ExVertex) = getData(cliq).upsolved +isUpInferenceComplete(cliq::TreeClique) = getData(cliq).upsolved -function areCliqVariablesAllInitialized(dfg::G, cliq::Graphs.ExVertex) where {G <: AbstractDFG} +function areCliqVariablesAllInitialized(dfg::G, cliq::TreeClique) where {G <: AbstractDFG} allids = getCliqAllVarIds(cliq) isallinit = true for vid in allids @@ -208,7 +208,7 @@ end Determine if this `cliq` has been fully initialized and child cliques have completed their full upward inference. """ -function isCliqReadyInferenceUp(fgl::FactorGraph, tree::BayesTree, cliq::Graphs.ExVertex) +function isCliqReadyInferenceUp(fgl::FactorGraph, tree::AbstractBayesTree, cliq::TreeClique) isallinit = areCliqVariablesAllInitialized(fgl, cliq) # check that all child cliques have also completed full up inference. @@ -223,7 +223,7 @@ end Blocking call until `cliq` upInit processes has arrived at a result. """ -function getCliqInitUpResultFromChannel(cliq::Graphs.ExVertex) +function getCliqInitUpResultFromChannel(cliq::TreeClique) status = take!(getData(cliq).initUpChannel) @info "$(current_task()) Clique $(cliq.index), dumping initUpChannel status, $status" return status @@ -245,16 +245,16 @@ Notes: - `:null` represents the first uninitialized state of a cliq. """ getCliqStatus(cliqdata::BayesTreeNodeData)::Symbol = cliqdata.initialized -getCliqStatus(cliq::Graphs.ExVertex)::Symbol = getCliqStatus(getData(cliq)) +getCliqStatus(cliq::TreeClique)::Symbol = getCliqStatus(getData(cliq)) -getCliqStatusUp(cliq::Graphs.ExVertex)::Symbol = getCliqStatus(cliq) +getCliqStatusUp(cliq::TreeClique)::Symbol = getCliqStatus(cliq) """ $SIGNATURES Set up initialization or solve status of this `cliq`. """ -function setCliqStatus!(cliq::Graphs.ExVertex, status::Symbol) +function setCliqStatus!(cliq::TreeClique, status::Symbol) getData(cliq).initialized = status end @@ -267,7 +267,7 @@ end Return true if all variables in clique are considered marginalized (and initialized). """ function areCliqVariablesAllMarginalized(subfg::AbstractDFG, - cliq::Graphs.ExVertex) + cliq::TreeClique) for vsym in getCliqAllVarIds(cliq) vert = getVariable(subfg, vsym) if !isMarginalized(vert) || !isInitialized(vert) @@ -284,9 +284,9 @@ end Set all Bayes (Junction) tree cliques that have all marginalized and initialized variables. """ function setTreeCliquesMarginalized!(dfg::G, - tree::BayesTree) where G <: AbstractDFG + tree::AbstractBayesTree) where G <: AbstractDFG # - for (cliid, cliq) in tree.cliques + for (cliid, cliq) in getCliques(tree) if areCliqVariablesAllMarginalized(dfg, cliq) # need to set the upward messages msgs = prepCliqInitMsgsUp(dfg, cliq) @@ -306,9 +306,9 @@ function setTreeCliquesMarginalized!(dfg::G, end -function blockCliqUntilParentDownSolved(prnt::Graphs.ExVertex; logger=ConsoleLogger())::Nothing +function blockCliqUntilParentDownSolved(prnt::TreeClique; logger=ConsoleLogger())::Nothing # - lbl = prnt.attributes["label"] + lbl = getLabel(prnt) with_logger(logger) do @info "blockCliqUntilParentDownSolved, prntcliq=$(prnt.index) | $lbl | going to fetch initdownchannel..." @@ -335,7 +335,7 @@ end """ $SIGNATURES -Block the thread until child cliques of `prnt::Graphs.ExVertex` have finished +Block the thread until child cliques of `prnt::TreeClique` have finished attempting upward initialization -- i.e. have status result. Return `::Dict{Symbol}` indicating whether next action that should be taken for each child clique. @@ -344,8 +344,8 @@ Notes: - See status options at `getCliqStatusUp(..)`. - Can be called multiple times """ -function blockCliqUntilChildrenHaveUpStatus(tree::BayesTree, - prnt::Graphs.ExVertex, +function blockCliqUntilChildrenHaveUpStatus(tree::AbstractBayesTree, + prnt::TreeClique, logger=ConsoleLogger() )::Dict{Int, Symbol} # ret = Dict{Int, Symbol}() @@ -375,8 +375,8 @@ Notes - used for regulating long need down message chains. - exit strategy is parent becomes status `:initialized`. """ -function blockCliqSiblingsParentNeedDown(tree::BayesTree, - cliq::Graphs.ExVertex; logger=ConsoleLogger()) +function blockCliqSiblingsParentNeedDown(tree::AbstractBayesTree, + cliq::TreeClique; logger=ConsoleLogger()) # with_logger(logger) do @info "cliq $(cliq.index), blockCliqSiblingsParentNeedDown -- start of function" @@ -474,8 +474,8 @@ end Update `subfg<:AbstractDFG` according to internal computations for a full upsolve. """ function doCliqUpSolve!(subfg::G, - tree::BayesTree, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + cliq::TreeClique; multiproc::Bool=true, logger=ConsoleLogger() )::Symbol where G <: AbstractDFG # @@ -492,7 +492,7 @@ end Prepare the upward inference messages from clique to parent and return as `Dict{Symbol}`. """ function prepCliqInitMsgsUp(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, logger=ConsoleLogger() )::TempBeliefMsg where G <: AbstractDFG # # construct init's up msg to place in parent from initialized separator variables @@ -510,8 +510,8 @@ function prepCliqInitMsgsUp(subfg::G, return msg end -function prepCliqInitMsgsUp(subfg::G, tree::BayesTree, cliq::Graphs.ExVertex)::TempBeliefMsg where G <: AbstractDFG - @warn "deprecated, use prepCliqInitMsgsUp(subfg::FactorGraph, cliq::Graphs.ExVertex) instead" +function prepCliqInitMsgsUp(subfg::G, tree::AbstractBayesTree, cliq::TreeClique)::TempBeliefMsg where G <: AbstractDFG + @warn "deprecated, use prepCliqInitMsgsUp(subfg::FactorGraph, cliq::TreeClique) instead" prepCliqInitMsgsUp(subfg, cliq) end @@ -528,8 +528,8 @@ Notes - must use factors in cliq only, ensured by using subgraph -- TODO general case. """ function doCliqAutoInitUpPart1!(subfg::G, - tree::BayesTree, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + cliq::TreeClique; up_solve_if_able::Bool=true, multiproc::Bool=true, logger=ConsoleLogger() ) where {G <: AbstractDFG} @@ -571,8 +571,8 @@ Notes - must use factors in cliq only, ensured by using subgraph -- TODO general case. """ function doCliqAutoInitUpPart2!(subfg::G, - tree::BayesTree, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + cliq::TreeClique; # msgfcts; up_solve_if_able::Bool=true, multiproc::Bool=true, @@ -682,8 +682,8 @@ end function condenseDownMsgsProductPrntFactors!(fgl::G, products, msgspervar, - prnt::Graphs.ExVertex, - cliq::Graphs.ExVertex, + prnt::TreeClique, + cliq::TreeClique, logger=ConsoleLogger() ) where G <: AbstractDFG # @@ -765,9 +765,9 @@ Dev Notes - This should be the initialization cycle of parent, build up bit by bit... """ function prepCliqInitMsgsDown!(fgl::G, - tree::BayesTree, - prnt::Graphs.ExVertex, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + prnt::TreeClique, + cliq::TreeClique; logger=ConsoleLogger(), dbgnew::Bool=true ) where G <: AbstractDFG # @@ -851,7 +851,7 @@ Dev Notes - TODO replace with nested 'minimum degree' type variable ordering. """ function getCliqInitVarOrderDown(dfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, downmsgs::TempBeliefMsg )::Vector{Symbol} where G <: AbstractDFG # allsyms = getCliqAllVarIds(cliq) @@ -990,8 +990,8 @@ end Return true or false depending on whether child cliques are all up solved. """ -function areCliqChildrenAllUpSolved(treel::BayesTree, - prnt::Graphs.ExVertex)::Bool +function areCliqChildrenAllUpSolved(treel::AbstractBayesTree, + prnt::TreeClique)::Bool # for ch in getChildren(treel, prnt) if !isCliqUpSolved(ch) @@ -1032,7 +1032,7 @@ Algorithm: - can only ever return :initialized or :needdownmsg status """ function doCliqInitDown!(subfg::G, - cliq::Graphs.ExVertex, + cliq::TreeClique, dwinmsgs::TempBeliefMsg; dbg::Bool=false, logpath::String="/tmp/caesar/", @@ -1080,8 +1080,8 @@ function doCliqInitDown!(subfg::G, end function doCliqInitDown!(subfg::G, - tree::BayesTree, - cliq::Graphs.ExVertex; + tree::AbstractBayesTree, + cliq::TreeClique; dbg::Bool=false ) where G <: AbstractDFG # @error "deprecated doCliqInitDown!(subfg, tree, cliq) use doCliqInitDown!(subfg, cliq, dwinmsgs) instead." @@ -1098,7 +1098,7 @@ end Return `true` if any of the children cliques have status `:needdownmsg`. """ -function areCliqChildrenNeedDownMsg(children::Vector{Graphs.ExVertex})::Bool +function areCliqChildrenNeedDownMsg(children::Vector{TreeClique})::Bool for ch in children if getCliqStatus(ch) == :needdownmsg return true @@ -1107,7 +1107,7 @@ function areCliqChildrenNeedDownMsg(children::Vector{Graphs.ExVertex})::Bool return false end -function areCliqChildrenNeedDownMsg(tree::BayesTree, cliq::Graphs.ExVertex)::Bool +function areCliqChildrenNeedDownMsg(tree::AbstractBayesTree, cliq::TreeClique)::Bool areCliqChildrenNeedDownMsg( getChildren(tree, cliq) ) end @@ -1117,7 +1117,7 @@ end Return true if has parent with status `:needdownmsg`. """ -function isCliqParentNeedDownMsg(tree::BayesTree, cliq::Graphs.ExVertex, logger=ConsoleLogger()) +function isCliqParentNeedDownMsg(tree::AbstractBayesTree, cliq::TreeClique, logger=ConsoleLogger()) prnt = getParent(tree, cliq) if length(prnt) == 0 return false diff --git a/test/runtests.jl b/test/runtests.jl index a8942ba95..b7d8cf4ac 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -24,6 +24,7 @@ include("testPartialFactors.jl") include("testBayesTreeiSAM2Example.jl") end +#FIXME fails on MetaBayesTree include("testTreeSaveLoad.jl") @testset "Ensure converter types can be run from extending namespaces..." begin @@ -58,7 +59,7 @@ include("testBasicGraphs.jl") include("testlocalconstraintexamples.jl") end -# include("testSolveOrphanedFG.jl") +include("testSolveOrphanedFG.jl") # include("priorusetest.jl") diff --git a/test/testBasicGraphs.jl b/test/testBasicGraphs.jl index 7b9d50bc8..fa5e4a27c 100644 --- a/test/testBasicGraphs.jl +++ b/test/testBasicGraphs.jl @@ -128,8 +128,8 @@ tree, smt, hist = solveTree!(fg) @test (getKDE(fg, :x0) |> getKDEMean .|> abs)[1] < 0.6 @test (getKDE(fg, :x1) |> getKDEMean .|> abs)[1] < 0.6 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 1.8 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 1.8 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 2.2 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 2.3 end diff --git a/test/testBayesTreeiSAM2Example.jl b/test/testBayesTreeiSAM2Example.jl index 681828f08..32ef003ad 100644 --- a/test/testBayesTreeiSAM2Example.jl +++ b/test/testBayesTreeiSAM2Example.jl @@ -47,7 +47,7 @@ global tree = emptyBayesTree() buildTree!(tree, fge, p) -@test num_vertices(tree.bt) == 3 +@test getNumCliqs(tree) == 3 # Michael reference -- x2->x1, x2->x3, x2->x4, x2->l1, x4->x3, l1->x3, l1->x4 diff --git a/test/testSolveOrphanedFG.jl b/test/testSolveOrphanedFG.jl index 3079897f1..c655020ad 100644 --- a/test/testSolveOrphanedFG.jl +++ b/test/testSolveOrphanedFG.jl @@ -5,7 +5,7 @@ using Test -@testset "Test forest of orphaned graphs" +@testset "Test forest of orphaned graphs" begin fg = initfg() addVariable!(fg, :x0, ContinuousScalar) @@ -13,12 +13,12 @@ addFactor!(fg, [:x0;], Prior(Normal())) addVariable!(fg, :x1, ContinuousScalar) addFactor!(fg, [:x0;:x1], LinearConditional(Normal())) -fg = initfg() addVariable!(fg, :x10, ContinuousScalar) addFactor!(fg, [:x10;], Prior(Normal())) addVariable!(fg, :x11, ContinuousScalar) addFactor!(fg, [:x10;:x11], LinearConditional(Normal())) +# dfgplot(fg) # solve factor graph with two orphaned components tree, smt, hist = solveTree!(fg) diff --git a/test/unittests/FactorGraph01_tests.jl b/test/unittests/FactorGraph01_tests.jl index bb3132a79..f1f9fade5 100644 --- a/test/unittests/FactorGraph01_tests.jl +++ b/test/unittests/FactorGraph01_tests.jl @@ -98,7 +98,7 @@ cliq = whichCliq(tree, :x1) # 0 -children = Graphs.ExVertex[] +children = TreeClique[] for ch in Graphs.out_neighbors(cliq, tree.bt) push!(children, ch) end From 010fde3009d2b492e200695bf4b1f725f737988b Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 00:05:52 -0500 Subject: [PATCH 32/57] general maintenance and improvements --- src/CliqStateMachineUtils.jl | 3 +- src/FGOSUtils.jl | 55 ++++++++++++++++++++++++++++++++++++ src/FactorGraphTypes.jl | 8 +++--- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index fe89d06dc..b468b62e4 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -679,7 +679,8 @@ Related calcVariablePPE """ -function setVariablePosteriorEstimates!(var::DFG.DFGVariable, solveKey::Symbol=:default)::DFG.DFGVariable +function setVariablePosteriorEstimates!(var::DFG.DFGVariable, + solveKey::Symbol=:default)::DFG.DFGVariable vnd = solverData(var, solveKey) diff --git a/src/FGOSUtils.jl b/src/FGOSUtils.jl index 7398cea2c..7fcd71eb4 100644 --- a/src/FGOSUtils.jl +++ b/src/FGOSUtils.jl @@ -4,6 +4,11 @@ import DistributedFactorGraphs: AbstractPointParametricEst + +export getPPESuggestedAll, findVariablesNear + + + # export setSolvable! @@ -345,7 +350,56 @@ function resetVariableAllInitializations!(fgl::FactorGraph) end +""" + $SIGNATURES + +Return `::Tuple` with matching variable ID symbols and `Suggested` PPE values. + +Related +getVariablePPE +""" +function getPPESuggestedAll(dfg::AbstractDFG, + regexFilter::Union{Nothing, Regex}=nothing )::Tuple{Vector{Symbol}, Matrix{Float64}} + # + # get values + vsyms = getVariableIds(dfg, regexFilter) |> sortDFG + slamPPE = map(x->getVariablePPE(dfg, x), vsyms) + # sizes to convert to matrix + rumax = zeros(Int, 2) + for varr in slamPPE + rumax[2] = length(varr) + rumax[1] = maximum(rumax) + end + + # populate with values + XYT = zeros(length(slamPPE),rumax[1]) + for i in 1:length(slamPPE) + XYT[i,1:length(slamPPE[i])] = slamPPE[i] + end + return (vsyms, XYT) +end + +""" + $SIGNATURES + +Find and return a `::Tuple` of variables and distances to `loc::Vector{<:Real}`. + +Related + +findVariablesNearTimestamp +""" +function findVariablesNear(dfg::AbstractDFG, + loc::Vector{<:Real}, + regexFilter::Union{Nothing, Regex}=nothing; + number::Int=3 ) + # + + xy = getPPESuggestedAll(dfg, regexFilter) + dist = sum( (xy[2][:,1:length(loc)] .- loc').^2, dims=2) |> vec + prm = (dist |> sortperm)[1:number] + return (xy[1][prm], sqrt.(dist[prm])) +end function convert(::Type{Tuple{BallTreeDensity,Float64}}, @@ -361,4 +415,5 @@ end + # diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index afe0765cc..6005b5cef 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -157,10 +157,10 @@ end Initialize an empty in-memory DistributedFactorGraph `::DistributedFactorGraph` object. """ function initfg(dfg::T=InMemDFGType(params=SolverParams()); - sessionname="NA", - robotname="", - username="", - cloudgraph=nothing)::T where T <: AbstractDFG + sessionname="NA", + robotname="", + username="", + cloudgraph=nothing)::T where T <: AbstractDFG # return dfg end From 3b7f91ff4e37c5e5860b694c2cece807849d1f62 Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 00:32:47 -0500 Subject: [PATCH 33/57] relax tests slightly --- test/testBasicGraphs.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testBasicGraphs.jl b/test/testBasicGraphs.jl index fa5e4a27c..29a82a1b5 100644 --- a/test/testBasicGraphs.jl +++ b/test/testBasicGraphs.jl @@ -225,9 +225,9 @@ X4 = (getKDE(fg, :x4) |> getKDEMean)[1] @test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 2.3 @test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 2.3 -@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x2))[1,:] ) < 2.3 -@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x3))[1,:] ) < 2.3 -@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x4))[1,:] ) < 2.3 +@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x2))[1,:] ) < 2.4 +@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x3))[1,:] ) < 2.4 +@test 0.2 < Statistics.cov( getPoints(getKDE(fg, :x4))[1,:] ) < 2.5 end From 85e5887bab9f28cc05f826e06da00dd44fa677ab Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 00:45:54 -0500 Subject: [PATCH 34/57] drop Julia 1.1 testing to reduce load --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5177ee1fa..5b7367c59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ arch: julia: - 1.0 - - 1.1 - 1.2 - 1.3 - nightly From 705a105f9c04d09f263e606d5a9384c2a4948f2d Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 08:35:33 -0500 Subject: [PATCH 35/57] complete test, ready to merge --- test/testSolveOrphanedFG.jl | 46 +++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/test/testSolveOrphanedFG.jl b/test/testSolveOrphanedFG.jl index c655020ad..e5dcf435b 100644 --- a/test/testSolveOrphanedFG.jl +++ b/test/testSolveOrphanedFG.jl @@ -1,6 +1,7 @@ # test forest of graphs can solve with CSM, using IncrementalInference +using Statistics using Test @@ -9,20 +10,55 @@ using Test fg = initfg() addVariable!(fg, :x0, ContinuousScalar) -addFactor!(fg, [:x0;], Prior(Normal())) +addFactor!(fg, [:x0;], Prior(Normal(0,0.1))) addVariable!(fg, :x1, ContinuousScalar) -addFactor!(fg, [:x0;:x1], LinearConditional(Normal())) +addFactor!(fg, [:x0;:x1], LinearConditional(Normal(10,0.1))) +addVariable!(fg, :x2, ContinuousScalar) +addFactor!(fg, [:x1;:x2], LinearConditional(Normal(10,0.1))) addVariable!(fg, :x10, ContinuousScalar) addFactor!(fg, [:x10;], Prior(Normal())) addVariable!(fg, :x11, ContinuousScalar) -addFactor!(fg, [:x10;:x11], LinearConditional(Normal())) +addFactor!(fg, [:x10;:x11], LinearConditional(Normal(-10,1.0))) +addVariable!(fg, :x12, ContinuousScalar) +addFactor!(fg, [:x11;:x12], LinearConditional(Normal(-10,1.0))) # dfgplot(fg) +# getSolverParams(fg).drawtree = true +# getSolverParams(fg).showtree = true # solve factor graph with two orphaned components -tree, smt, hist = solveTree!(fg) +vo = Symbol[:x12, :x2, :x0, :x11, :x1, :x10] +tree, smt, hist = solveTree!(fg, variableOrder=vo) # test tree will have two different root nodes -# ... +@test getVariableOrder(tree) == vo + +@test getParent(tree, getCliq(tree, :x1)) |> length == 0 +@test getParent(tree, getCliq(tree, :x10)) |> length == 0 + +@test getChildren(tree, getCliq(tree, :x1)) |> length == 1 +@test getChildren(tree, getCliq(tree, :x10)) |> length == 1 + +@test getChildren(tree, getCliq(tree, :x2)) |> length == 0 +@test getChildren(tree, getCliq(tree, :x12)) |> length == 0 + + +## Test the numerical values are correct + +@test getKDE(fg, :x0) |> getPoints |> mean |> abs < 1.0 +@test (getKDE(fg, :x1) |> getPoints |> mean) - 10 |> abs < 2.0 +@test (getKDE(fg, :x2) |> getPoints |> mean) - 20 |> abs < 3.0 + +@test getKDE(fg, :x10) |> getPoints |> mean |> abs < 2.0 +@test (getKDE(fg, :x11) |> getPoints |> mean) + 10 |> abs < 4.0 +@test (getKDE(fg, :x12) |> getPoints |> mean) + 20 |> abs < 5.0 + + + +# using RoMEPlotting +# Gadfly.set_default_plot_size(35cm, 25cm) +# +# plotKDE(fg, ls(fg)) + end From ad73790d404365151bfe3c9db11292c325ad142a Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 08:39:13 -0500 Subject: [PATCH 36/57] add issue number comment --- test/testSolveOrphanedFG.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testSolveOrphanedFG.jl b/test/testSolveOrphanedFG.jl index e5dcf435b..d8d676bd1 100644 --- a/test/testSolveOrphanedFG.jl +++ b/test/testSolveOrphanedFG.jl @@ -1,4 +1,4 @@ -# test forest of graphs can solve with CSM, +# test forest of graphs can solve with CSM, specifically #518 using IncrementalInference using Statistics From 8d61d187893ac801320214135fa1e2f690be439d Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 09:01:40 -0500 Subject: [PATCH 37/57] bug fix for #530 --- src/SolveTree01.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 977be8185..0b036bd4e 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -1040,7 +1040,7 @@ function approxCliqMarginalUp!(fgl::G, # copy up and down msgs that may already exists #TODO Exists where? it copies from tree_ to tree if onduplicate - for (id, cliq) in tree_.cliques + for (id, cliq) in treel.cliques setUpMsg!(tree_.cliques[cliq.index], getUpMsgs(cliq)) #TODO cliq.index may be problematic, how do we know it will be the same index on rebuilding? setDwnMsg!(tree_.cliques[cliq.index], getDwnMsgs(cliq)) end From 12bd1647e00cb5f5de3a4cf3c03db6fbd798e1f3 Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 09:18:19 -0500 Subject: [PATCH 38/57] attempt to fix #527 --- test/runtests.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index b7d8cf4ac..c0241b76c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -96,9 +96,10 @@ end @warn "must return testExpandedJLD.jl to testing -- currently skipped since jld2 files cannot be loaded." # include("testExpandedJLD.jl") - -include("testTexTreeIllustration.jl") - +# dont run test on ARM, as per issue #527 +if Base.Sys.ARCH in [:x86_64;] + include("testTexTreeIllustration.jl") +end From 8c1210dcf9dd6314cdb85c0e3b7d374264e74dec Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 09:29:40 -0500 Subject: [PATCH 39/57] try to update travis before_script --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5b7367c59..6574a93f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ addons: - dot2tex before_script: - - pip install dot2tex + - if [ `arch` == x86_64 ]; then pip install dot2tex; fi # script: # - julia --color=yes -e 'using Pkg; Pkg.build()' From 29bf8c3022c8ff35a85b149fcaf2a571d37894bd Mon Sep 17 00:00:00 2001 From: antonio teran Date: Thu, 16 Jan 2020 12:43:48 -0500 Subject: [PATCH 40/57] remove RoME dependency and clean up the tree analysis plotting --- examples/TreeAnalysis.jl | 30 +++--------------------------- test/testAnalysisTools.jl | 1 - 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl index 8cd564ec6..cba888356 100644 --- a/examples/TreeAnalysis.jl +++ b/examples/TreeAnalysis.jl @@ -1,7 +1,6 @@ # Showcasing the available analysis tools for the Bayes (Junction) tree. using IncrementalInference using DistributedFactorGraphs # For `isSolvable` function. -using RoME # For loading canonical graphs (e.g., Kaess' example). using Combinatorics # For creating the variable ordering `permutations`. using SuiteSparse.CHOLMOD: SuiteSparse_long # For CCOLAMD constraints. using Gadfly # For histogram and scatter plots. @@ -34,32 +33,6 @@ all_nnzs = (x->(x[2])).(scores) costs_01 = (x->(x[3])).(scores) costs_02 = (x->(x[4])).(scores) -# HACKING -# plotting tricks with gadfly -# trick 1 -# using Colors -# PL = [] -# push!(PL, Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"red"))) -# push!(PL, Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"magenta"))) -# # push!(PL, ThemeLege...) -# pl = Gadfly.plot(PL...) -# -# pl |> typeof |> fieldnames -# # fieldnames(typeof(pl)) -# -# pl.coord = Coord.Cartesian(xmin=0,xmax=10,ymin=-5,ymax=2) -# -# pl -# pll = Gadfly.layer(x=1:10, y=randn(10),Geom.line, Theme(default_color=colorant"green")) -# union!(pl.layers, pll) -# pl -# pl |> SVG("/tmp/test.svg") -# using Cairo -# pl |> PDF("/tmp/test.pdf") -# pl |> PNG("/tmp/test.png") - - - min_ids_02 = findall(x->x == minimum(costs_02), costs_02) max_ids_02 = findall(x->x == maximum(costs_02), costs_02) @@ -116,3 +89,6 @@ pl = Gadfly.plot(layers..., Guide.manual_color_key("", ["AMD", "COLAMD", "iSAM2"], ["green", "blue", "red"])) + +img = SVG("vo_cost_canon_kaess.svg", 6inch, 6inch) +Gadfly.draw(img, pl) diff --git a/test/testAnalysisTools.jl b/test/testAnalysisTools.jl index d8b152c1f..ae7e234b7 100644 --- a/test/testAnalysisTools.jl +++ b/test/testAnalysisTools.jl @@ -1,7 +1,6 @@ # Test for tree-based analysis tools found in `AnalysisTools.jl`. using Test using IncrementalInference -using RoME # Used for loading canonical graphs (is this ok?). @testset "Number of non-zero calculation for frontals." begin # Alternative way of calculating number of upper triangular matrix elements. From c259912bd69be78e89132969230adefb83305b8f Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 13:06:47 -0500 Subject: [PATCH 41/57] updates and compat DocSExt min 0.8 --- Project.toml | 2 +- src/JunctionTreeTypes.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 6d0d5f92a..ee6f5aa7b 100644 --- a/Project.toml +++ b/Project.toml @@ -36,7 +36,7 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" ApproxManifoldProducts = "0.1, 0.2" DistributedFactorGraphs = "0.5.2" Distributions = "0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 1" -DocStringExtensions = "0.7, 0.8, 0.9, 0.10, 1" +DocStringExtensions = "0.8, 0.9, 0.10, 1" FileIO = "1.0.2, 1.1, 1.2" FunctionalStateMachine = "0.1, 0.2" Graphs = "0.10.2, 0.11, 1" diff --git a/src/JunctionTreeTypes.jl b/src/JunctionTreeTypes.jl index 87cdda464..216adb8c3 100644 --- a/src/JunctionTreeTypes.jl +++ b/src/JunctionTreeTypes.jl @@ -227,6 +227,8 @@ mutable struct CliqStateMachineContainer{BTND, T <: AbstractDFG, InMemG <: InMem # x13::SimpleLogger=SimpleLogger(Base.stdout) ) where {BTND, G <: AbstractDFG} = new{BTND, G, typeof(x2)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10a,x10aa,x10aaa,x10b,x11, x13) end +const CSMHistory = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}} + function CliqStateMachineContainer(x1::G, x2::InMemoryDFGTypes, x3::AbstractBayesTree, @@ -246,7 +248,6 @@ function CliqStateMachineContainer(x1::G, CliqStateMachineContainer{BTND, G, typeof(x2), typeof(x3)}(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x10aa,x10aaa,x10b,x11,x13) end -const CSMHistory = Vector{Tuple{DateTime, Int, Function, CliqStateMachineContainer}} """ From 9686831845eae4448aa49d315571a926032e8bb2 Mon Sep 17 00:00:00 2001 From: antonio teran Date: Thu, 16 Jan 2020 13:10:12 -0500 Subject: [PATCH 42/57] export functions and add tree analysis to included source files --- src/AnalysisTools.jl | 2 ++ src/IncrementalInference.jl | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl index d6c80dac1..56878c888 100644 --- a/src/AnalysisTools.jl +++ b/src/AnalysisTools.jl @@ -1,3 +1,5 @@ +export shrinkFactorGraph, getAllTrees, nnzFrontals, nnzClique, nnzTree, nnzSqrtInfoMatrix, getTreeCost_01, getTreeCost_02 + """ $SIGNATURES diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index a3b09b66e..701899260 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -561,6 +561,9 @@ include("SolverAPI.jl") include("CanonicalGraphExamples.jl") include("Deprecated.jl") +# Symbolic tree analysis files. +include("AnalysisTools.jl") + exportimg(pl) = error("Please do `using Gadfly` before IncrementalInference is used to allow image export.") function __init__() @require Gadfly="c91e804a-d5a3-530f-b6f0-dfbca275c004" begin From 4839a4113bf3974b7121b9bbc9b54eb4005f17c3 Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 14:33:58 -0500 Subject: [PATCH 43/57] make ccolamd usable, fixes #327 --- Project.toml | 1 + examples/TreeAnalysis.jl | 6 +++++- src/AnalysisTools.jl | 4 ++-- src/FactorGraph01.jl | 23 +++++++++++++++++++---- src/IncrementalInference.jl | 11 +++++++---- test/runtests.jl | 2 ++ test/testCcolamdOrdering.jl | 24 ++++++++++++++++++++++++ 7 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 test/testCcolamdOrdering.jl diff --git a/Project.toml b/Project.toml index ee6f5aa7b..970209778 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.8.3" [deps] ApproxManifoldProducts = "9bbbb610-88a1-53cd-9763-118ce10c1f89" +Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl index cba888356..e8af89ef1 100644 --- a/examples/TreeAnalysis.jl +++ b/examples/TreeAnalysis.jl @@ -1,9 +1,13 @@ # Showcasing the available analysis tools for the Bayes (Junction) tree. +# using Revise + using IncrementalInference using DistributedFactorGraphs # For `isSolvable` function. using Combinatorics # For creating the variable ordering `permutations`. using SuiteSparse.CHOLMOD: SuiteSparse_long # For CCOLAMD constraints. using Gadfly # For histogram and scatter plots. +Gadfly.set_default_plot_size(35cm,25cm) + latex_fonts = Theme(major_label_font="CMU Serif", major_label_font_size=16pt, minor_label_font="CMU Serif", minor_label_font_size=14pt, @@ -12,7 +16,7 @@ latex_fonts = Theme(major_label_font="CMU Serif", major_label_font_size=16pt, Gadfly.push_theme(latex_fonts) # Get tree for each variable ordering in a factor graph. -fg = loadCanonicalFG_Kaess() +fg = loadCanonicalFG_Kaess(graphinit=false) all_trees = getAllTrees(deepcopy(fg)) # scores stores: (tree key ID, nnz, cost fxn 1, cost fxn 2). diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl index 56878c888..d8c7c32e3 100644 --- a/src/AnalysisTools.jl +++ b/src/AnalysisTools.jl @@ -36,8 +36,8 @@ of `dfg` factor graph. Returns a dictionary with (tree, ordering, nnz) tuples. Warning: factorial number of possibilities, so use carefully! """ function getAllTrees(fg::AbstractDFG) - dfg = loadCanonicalFG_Kaess() - variables = ls(dfg) + # dfg = loadCanonicalFG_Kaess(graphinit=false) + variables = ls(fg) orderings = permutations(variables) |> collect # Dimensionality check to make sure we do not break your computer. diff --git a/src/FactorGraph01.jl b/src/FactorGraph01.jl index 5c2b338ff..7e176c390 100644 --- a/src/FactorGraph01.jl +++ b/src/FactorGraph01.jl @@ -1081,26 +1081,41 @@ Future - TODO: `A` should be sparse data structure (when we exceed 10'000 var dims) - TODO: Incidence matrix is rectagular and adjacency is the square. """ -function getEliminationOrder(dfg::G; ordering::Symbol=:qr, solvable::Int=1) where G <: AbstractDFG +function getEliminationOrder(dfg::G; + ordering::Symbol=:qr, + solvable::Int=1, + constraints::Vector{Symbol}=Symbol[]) where G <: AbstractDFG + # + @assert 0 == length(constraints) || ordering == :ccolamd "Must use ordering=:ccolamd when trying to use constraints" # Get the sparse adjacency matrix, variable, and factor labels adjMat, permuteds, permutedsf = DFG.getAdjacencyMatrixSparse(dfg, solvable=solvable) # Create dense adjacency matrix - A = Array(adjMat) p = Int[] if ordering==:chol - p = cholfact(A'A,:U,Val(true))[:p] #,pivot=true + # hack for dense matrix.... + A = Array(adjMat) + p = cholfact(A'A,:U,Val(true))[:p] #,pivot=true + @warn "check cholesky ordering is not reversed -- basically how much fill in (separator size) are you seeing??? Long skinny chains in tree is bad." elseif ordering==:qr + # hack for dense matrix.... + A = Array(adjMat) # this is the default q,r,p = qr(A, Val(true)) + p .= p |> reverse + elseif ordering==:ccolamd + cons = zeros(SuiteSparse_long, length(adjMat.colptr) - 1) + cons[findall(x->x in constraints, permuteds)] .= 1 + p = Ccolamd.ccolamd(adjMat, cons) + @warn "Ccolamd is experimental in IIF at this point in time." else prtslperr("getEliminationOrder -- cannot do the requested ordering $(ordering)") end # Return the variable ordering that we should use for the Bayes map # reverse order checked in #475 and #499 - return permuteds[p] |> reverse + return permuteds[p] end diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index bbb2c8e84..f63a9127f 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -26,10 +26,16 @@ using DocStringExtensions, FunctionalStateMachine, Optim, # might be deprecated in favor for only NLsolve dependency - JSON2 + JSON2, + Combinatorics using Logging +# bringing in BSD 3-clause ccolamd +include("ccolamd.jl") +using SuiteSparse.CHOLMOD: SuiteSparse_long # For CCOLAMD constraints. +using .Ccolamd + const KDE = KernelDensityEstimate const AMP = ApproxManifoldProducts const DFG = DistributedFactorGraphs @@ -511,9 +517,6 @@ export # TODO should be deprecated const NothingUnion{T} = Union{Nothing, T} -# non-free, but not currently use! -include("ccolamd.jl") - # regular include("FactorGraphTypes.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 56f49931e..965a6fd95 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -52,6 +52,8 @@ include("testBasicCSM.jl") include("testCliqueFactors.jl") +include("testCcolamdOrdering.jl") + include("testBasicGraphs.jl") @testset "with simple local constraint examples Odo, Obsv2..." begin diff --git a/test/testCcolamdOrdering.jl b/test/testCcolamdOrdering.jl new file mode 100644 index 000000000..1219c7c1e --- /dev/null +++ b/test/testCcolamdOrdering.jl @@ -0,0 +1,24 @@ +using IncrementalInference +using Test + + +@testset "Test ccolamd for constrained variable ordering" + +fg = loadCanonicalFG_Kaess(graphinit=false) + +vo = getEliminationOrder(fg, constraints=[:x3], ordering=:ccolamd) + +@test vo[end] == :x3 +@test length(vo) == length(ls(fg)) + +vo = getEliminationOrder(fg, constraints=[:l2], ordering=:ccolamd) + +@test vo[end] == :l2 + + +vo = getEliminationOrder(fg, constraints=[:x3;:l2], ordering=:ccolamd) + +@test intersect(vo[end-1:end], [:x3;:l2]) |> length == 2 + + +end From 9f6f5eadef0b209b2a131dd5ce6153ec12575edf Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 14:59:23 -0500 Subject: [PATCH 44/57] oops, add begin statement --- test/testCcolamdOrdering.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testCcolamdOrdering.jl b/test/testCcolamdOrdering.jl index 1219c7c1e..180827533 100644 --- a/test/testCcolamdOrdering.jl +++ b/test/testCcolamdOrdering.jl @@ -2,7 +2,7 @@ using IncrementalInference using Test -@testset "Test ccolamd for constrained variable ordering" +@testset "Test ccolamd for constrained variable ordering" begin fg = loadCanonicalFG_Kaess(graphinit=false) From b6abfb0cd23f07718ca0196fb90f56a757c48298 Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 15:23:09 -0500 Subject: [PATCH 45/57] load -> generateCanonicalFG_ --- examples/TreeAnalysis.jl | 2 +- src/AnalysisTools.jl | 2 +- src/CanonicalGraphExamples.jl | 8 ++++---- test/testAnalysisTools.jl | 4 ++-- test/testCcolamdOrdering.jl | 2 +- test/testJunctionTreeConstruction.jl | 6 +++--- test/testTreeSaveLoad.jl | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/TreeAnalysis.jl b/examples/TreeAnalysis.jl index e8af89ef1..035c9678e 100644 --- a/examples/TreeAnalysis.jl +++ b/examples/TreeAnalysis.jl @@ -16,7 +16,7 @@ latex_fonts = Theme(major_label_font="CMU Serif", major_label_font_size=16pt, Gadfly.push_theme(latex_fonts) # Get tree for each variable ordering in a factor graph. -fg = loadCanonicalFG_Kaess(graphinit=false) +fg = generateCanonicalFG_Kaess(graphinit=false) all_trees = getAllTrees(deepcopy(fg)) # scores stores: (tree key ID, nnz, cost fxn 1, cost fxn 2). diff --git a/src/AnalysisTools.jl b/src/AnalysisTools.jl index d8c7c32e3..a48c9a4cf 100644 --- a/src/AnalysisTools.jl +++ b/src/AnalysisTools.jl @@ -36,7 +36,7 @@ of `dfg` factor graph. Returns a dictionary with (tree, ordering, nnz) tuples. Warning: factorial number of possibilities, so use carefully! """ function getAllTrees(fg::AbstractDFG) - # dfg = loadCanonicalFG_Kaess(graphinit=false) + # dfg = generateCanonicalFG_Kaess(graphinit=false) variables = ls(fg) orderings = permutations(variables) |> collect diff --git a/src/CanonicalGraphExamples.jl b/src/CanonicalGraphExamples.jl index f065493d5..09c546f76 100644 --- a/src/CanonicalGraphExamples.jl +++ b/src/CanonicalGraphExamples.jl @@ -1,5 +1,5 @@ -export loadCanonicalFG_Kaess, loadCanonicalFG_TestSymbolic, loadCanonicalFG_CaesarRing1D, generateCanonicalFG_lineStep +export generateCanonicalFG_Kaess, generateCanonicalFG_TestSymbolic, generateCanonicalFG_CaesarRing1D, generateCanonicalFG_lineStep """ $SIGNATURES @@ -9,7 +9,7 @@ Canonical example from literature, Kaess, et al.: ISAM2, IJRR, 2011. Notes - Paper variable ordering: p = [:l1;:l2;:x1;:x2;:x3] """ -function loadCanonicalFG_Kaess(;graphinit::Bool=false) +function generateCanonicalFG_Kaess(;graphinit::Bool=false) fg = initfg() addVariable!(fg,:x1, ContinuousScalar) @@ -41,7 +41,7 @@ Canonical example introduced by Borglab. Notes - Known variable ordering: p = [:x1; :l3; :l1; :x5; :x2; :l2; :x4; :x3] """ -function loadCanonicalFG_TestSymbolic(;graphinit::Bool=false) +function generateCanonicalFG_TestSymbolic(;graphinit::Bool=false) fg = initfg() addVariable!(fg, :x1, ContinuousScalar) @@ -77,7 +77,7 @@ Canonical example introduced originally as Caesar Hex Example. Notes - Paper variable ordering: p = [:x0;:x2;:x4;:x6;:x1;:l1;:x5;:x3;] """ -function loadCanonicalFG_CaesarRing1D(;graphinit::Bool=false) +function generateCanonicalFG_CaesarRing1D(;graphinit::Bool=false) fg = initfg() diff --git a/test/testAnalysisTools.jl b/test/testAnalysisTools.jl index ae7e234b7..ec0b43242 100644 --- a/test/testAnalysisTools.jl +++ b/test/testAnalysisTools.jl @@ -12,7 +12,7 @@ using IncrementalInference end @testset "Number of non-zero calculation for full cliques." begin - fg = loadCanonicalFG_Kaess() + fg = generateCanonicalFG_Kaess() vo = [:l1, :l2, :x1, :x2, :x3] tree = buildTreeFromOrdering!(fg, vo) # Must agree with hand-calculated values, iSAM2 paper. @@ -22,7 +22,7 @@ end end @testset "Number of non-zero calculation for full trees." begin - fg = loadCanonicalFG_Kaess() + fg = generateCanonicalFG_Kaess() vo = [:l1, :l2, :x1, :x2, :x3] tree = buildTreeFromOrdering!(fg, vo) # Must agree with hand-calculated values, iSAM2 paper. diff --git a/test/testCcolamdOrdering.jl b/test/testCcolamdOrdering.jl index 180827533..d4d856bd0 100644 --- a/test/testCcolamdOrdering.jl +++ b/test/testCcolamdOrdering.jl @@ -4,7 +4,7 @@ using Test @testset "Test ccolamd for constrained variable ordering" begin -fg = loadCanonicalFG_Kaess(graphinit=false) +fg = generateCanonicalFG_Kaess(graphinit=false) vo = getEliminationOrder(fg, constraints=[:x3], ordering=:ccolamd) diff --git a/test/testJunctionTreeConstruction.jl b/test/testJunctionTreeConstruction.jl index fc6f4c733..ced9d900e 100644 --- a/test/testJunctionTreeConstruction.jl +++ b/test/testJunctionTreeConstruction.jl @@ -6,7 +6,7 @@ using Test @testset "Variable ordering Bayes tree member check." begin - fg = loadCanonicalFG_Kaess() + fg = generateCanonicalFG_Kaess() # Choose specific variable ordering and perform check. vo = [:l1, :l2, :x1, :x2, :x3] tree = buildTreeFromOrdering!(fg, vo) @@ -18,7 +18,7 @@ end @testset "Test Caesar Ring 1D symbolic tree construction" begin -fg = loadCanonicalFG_CaesarRing1D() +fg = generateCanonicalFG_CaesarRing1D() # drawGraph(fg, show=true) eo = [:x0;:x2;:x4;:x6;:x1;:l1;:x5;:x3;] @@ -68,7 +68,7 @@ end @testset "Test tree formation and consistent APIs" begin - fg = loadCanonicalFG_TestSymbolic() + fg = generateCanonicalFG_TestSymbolic() #writeGraphPdf(fg, show=true) diff --git a/test/testTreeSaveLoad.jl b/test/testTreeSaveLoad.jl index 1873de11e..48f32681f 100644 --- a/test/testTreeSaveLoad.jl +++ b/test/testTreeSaveLoad.jl @@ -5,7 +5,7 @@ using IncrementalInference @testset "Test loading and saving of Bayes (Junction) tree" begin - fg = loadCanonicalFG_Kaess(graphinit=false) + fg = generateCanonicalFG_Kaess(graphinit=false) tree = wipeBuildNewTree!(fg) # save and load tree @@ -30,7 +30,7 @@ end @testset "Test loading and saving of Bayes (Junction) tree" begin - fg = loadCanonicalFG_Kaess(graphinit=false) + fg = generateCanonicalFG_Kaess(graphinit=false) tree = wipeBuildNewTree!(fg) # save and load tree as array From 9dde3815661c95d30f72b3c8344815073bff9d47 Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 16:25:05 -0500 Subject: [PATCH 46/57] fix #489 spyCliqMat --- src/IncrementalInference.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index f63a9127f..d2897ebbe 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -597,6 +597,9 @@ function __init__() @show getData(cliq).directFrtlMsgIDs @show getData(cliq).directPriorMsgIDs end + if size(mat,1) == 1 + mat = [mat; -ones(size(mat,2))'] + end sp = Gadfly.spy(mat) push!(sp.guides, Gadfly.Guide.title("$(getLabel(cliq)) || $(getData(cliq).frontalIDs) :$(getData(cliq).separatorIDs)")) push!(sp.guides, Gadfly.Guide.xlabel("fmcmcs $(getData(cliq).itervarIDs)")) From 4a7ae7175e07a35f790e5c244daf2220bbafc57c Mon Sep 17 00:00:00 2001 From: dehann Date: Thu, 16 Jan 2020 16:38:38 -0500 Subject: [PATCH 47/57] bump v0.8.4 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 970209778..19ced55db 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "IncrementalInference" uuid = "904591bb-b899-562f-9e6f-b8df64c7d480" keywords = ["mm-iSAM", "SLAM", "inference", "sum-product", "belief-propagation"] desc = "Implements the multimodal iSAM algorithm." -version = "0.8.3" +version = "0.8.4" [deps] ApproxManifoldProducts = "9bbbb610-88a1-53cd-9763-118ce10c1f89" From d0b0fc7f4809418d719f37f913fa8517d9893825 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Jan 2020 22:09:24 +0000 Subject: [PATCH 48/57] CompatHelper: add new compat entry for "Combinatorics" at version "1.0" --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 19ced55db..f52dd7e61 100644 --- a/Project.toml +++ b/Project.toml @@ -35,6 +35,7 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [compat] ApproxManifoldProducts = "0.1, 0.2" +Combinatorics = "1.0" DistributedFactorGraphs = "0.5.2" Distributions = "0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 1" DocStringExtensions = "0.8, 0.9, 0.10, 1" From 710f99d0edda208d5febd17575d7652c7e95e9d9 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 00:44:19 -0500 Subject: [PATCH 49/57] fix PPE set during solve --- src/CliqStateMachineUtils.jl | 9 ++++-- src/FGOSUtils.jl | 4 +++ src/FactorGraphTypes.jl | 24 ++++++++------ src/IncrementalInference.jl | 1 + test/runtests.jl | 2 ++ test/testSolveSetPPE.jl | 62 ++++++++++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 test/testSolveSetPPE.jl diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index 8d6b1dfa7..247fd54e0 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -1,3 +1,6 @@ + +export setVariablePosteriorEstimates! + """ $SIGNATURES @@ -16,7 +19,9 @@ function dbgSaveDFG(dfg::AbstractDFG, # folder::String=joinpath(opts.logpath,"logs") if opts.dbg - ispath(folder) && mkpath(folder) + if !ispath(folder) + mkpath(folder) + end DFG.saveDFG(dfg, joinpath(folder, "$filename")) drawGraph(dfg, show=false, filepath=joinpath(folder, "$filename.pdf")) end @@ -675,7 +680,7 @@ DevNotes Related -calcVariablePPE +calcVariablePPE, getVariablePPE, (setVariablePPE!/setPPE!/updatePPE! ?) """ function setVariablePosteriorEstimates!(var::DFG.DFGVariable, solveKey::Symbol=:default)::DFG.DFGVariable diff --git a/src/FGOSUtils.jl b/src/FGOSUtils.jl index 7fcd71eb4..9347f622d 100644 --- a/src/FGOSUtils.jl +++ b/src/FGOSUtils.jl @@ -82,6 +82,10 @@ Get the ParametricPointEstimates---based on full marginal belief estimates---of DevNotes - TODO update for manifold subgroups. + +Related + +getVariablePPE, setVariablePosteriorEstimates!, getVariablePPE! """ function calcVariablePPE(var::DFGVariable, softt::InferenceVariable; diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index 615d97347..07f87a55b 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -356,23 +356,29 @@ end # excessive function, needs refactoring function updateFullVertData!(fgl::AbstractDFG, - nv::DFGNode; + srcv::DFGNode; updateMAPest::Bool=false ) # @warn "Deprecated updateFullVertData!, need alternative" - sym = Symbol(nv.label) + sym = Symbol(srcv.label) isvar = isVariable(fgl, sym) - lvert = isvar ? DFG.getVariable(fgl, sym) : DFG.getFactor(fgl, sym) - lvd = solverData(lvert) - nvd = solverData(nv) + dest = isvar ? DFG.getVariable(fgl, sym) : DFG.getFactor(fgl, sym) + lvd = solverData(dest) + srcvd = solverData(srcv) if isvar - lvd.val[:,:] = nvd.val[:,:] - lvd.bw[:] = nvd.bw[:] - lvd.initialized = nvd.initialized - lvd.inferdim = nvd.inferdim + lvd.val[:,:] = srcvd.val[:,:] + lvd.bw[:] = srcvd.bw[:] + lvd.initialized = srcvd.initialized + lvd.inferdim = srcvd.inferdim + + if updateMAPest + # set PPE in dest from values in srcv + # TODO must work for all keys involved + getEstimates(dest)[:default] = getEstimates(srcv)[:default] + end else # assuming nothing to be done end diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index d2897ebbe..40e975456 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -70,6 +70,7 @@ export AbstractDFG, hasVariable, getSolverParams, + LightDFG, *, notifyCSMCondition, diff --git a/test/runtests.jl b/test/runtests.jl index 965a6fd95..9d2ebde4a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -63,6 +63,8 @@ end include("testSolveOrphanedFG.jl") +include("testSolveSetPPE.jl") + # include("priorusetest.jl") include("testExplicitMultihypo.jl") diff --git a/test/testSolveSetPPE.jl b/test/testSolveSetPPE.jl new file mode 100644 index 000000000..832f8b8f9 --- /dev/null +++ b/test/testSolveSetPPE.jl @@ -0,0 +1,62 @@ +# test that PPE values are update with solve, see issue #548 + +using Test +using IncrementalInference +using DistributedFactorGraphs + +@testset "test PPE update during solve" begin + +fg = generateCanonicalFG_Kaess(graphinit=true) +ensureAllInitialized!(fg) + +# list of variables to check +vars = getVariableIds(fg) + +# fetch values before solve +before = Dict() +for vs in vars + before[vs] = getVariablePPE(getVariable(fg, vs)) +end + +# do the solve +# getSolverParams(fg).dbg = true + +# tree = wipeBuildNewTree!(fg) +# drawTree(tree, show=true) + +# solveCliq!(fg, tree, :l2) +# solveCliq!(fg, tree, :x3) +# solveCliq!(fg, tree, :x2) + +solveTree!(fg) + + +after = Dict() +for vs in vars + after[vs] = getVariablePPE(getVariable(fg, vs)) +end + +# before and after should be noticably different, because first inferred values have been found +for vs in vars + errd = norm(before[vs] - after[vs]) + # @show vs, errd + @test 1e-5 < errd +end + +# force recalc and update each PPE +force = Dict() +for vs in vars + setVariablePosteriorEstimates!(fg, vs) + force[vs] = getVariablePPE(getVariable(fg, vs)) + # these need to be close to the same as after + errd = norm(force[vs] - after[vs]) + # @show vs, errd + @test errd < 0.1 +end + + + +## suspect cliqSubFg updated, but not back to main dfg object... test via load graph + + +end From 658247ebc0f64c580bc9bb0e6dc61deb0296f250 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 00:59:50 -0500 Subject: [PATCH 50/57] missing import --- test/testSolveSetPPE.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/testSolveSetPPE.jl b/test/testSolveSetPPE.jl index 832f8b8f9..13da13dd9 100644 --- a/test/testSolveSetPPE.jl +++ b/test/testSolveSetPPE.jl @@ -4,6 +4,8 @@ using Test using IncrementalInference using DistributedFactorGraphs +import DistributedFactorGraphs: getEstimates + @testset "test PPE update during solve" begin fg = generateCanonicalFG_Kaess(graphinit=true) From 3e313aba578f70f4ab21c667bf56bcfe9f2069af Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 01:10:31 -0500 Subject: [PATCH 51/57] oops, import in wrong place --- src/IncrementalInference.jl | 1 + test/testSolveSetPPE.jl | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index 40e975456..b804bb1de 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -48,6 +48,7 @@ import Random: rand, rand! import KernelDensityEstimate: getBW import ApproxManifoldProducts: kde!, manikde! import DistributedFactorGraphs: addVariable!, addFactor!, ls, lsf, isInitialized, hasOrphans, compare, compareAllSpecial +import DistributedFactorGraphs: getEstimates # missing exports import DistributedFactorGraphs: PackedFunctionNodeData, FunctionNodeData diff --git a/test/testSolveSetPPE.jl b/test/testSolveSetPPE.jl index 13da13dd9..65278d9f2 100644 --- a/test/testSolveSetPPE.jl +++ b/test/testSolveSetPPE.jl @@ -4,7 +4,6 @@ using Test using IncrementalInference using DistributedFactorGraphs -import DistributedFactorGraphs: getEstimates @testset "test PPE update during solve" begin From ba3b490704fc02f72a01b5c4b3c2ae3b55d01c85 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:00:49 -0500 Subject: [PATCH 52/57] use ppeDict from DFG v0.5.3 --- Project.toml | 2 +- src/CliqStateMachineUtils.jl | 4 ++-- src/FactorGraphTypes.jl | 2 +- src/IncrementalInference.jl | 2 +- test/testCompareVariablesFactors.jl | 4 ++-- test/testSolveSetPPE.jl | 7 +++---- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index 19ced55db..76ca45bf7 100644 --- a/Project.toml +++ b/Project.toml @@ -35,7 +35,7 @@ SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [compat] ApproxManifoldProducts = "0.1, 0.2" -DistributedFactorGraphs = "0.5.2" +DistributedFactorGraphs = "0.5.3" Distributions = "0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 1" DocStringExtensions = "0.8, 0.9, 0.10, 1" FileIO = "1.0.2, 1.1, 1.2" diff --git a/src/CliqStateMachineUtils.jl b/src/CliqStateMachineUtils.jl index 247fd54e0..c4d9305ef 100644 --- a/src/CliqStateMachineUtils.jl +++ b/src/CliqStateMachineUtils.jl @@ -687,8 +687,8 @@ function setVariablePosteriorEstimates!(var::DFG.DFGVariable, vnd = solverData(var, solveKey) - #TODO in the future one can perhaps populate other solver data types here by looking at the typeof estimateDict entries - var.estimateDict[solveKey] = calcVariablePPE(var, method=MeanMaxPPE, solveKey=solveKey) + #TODO in the future one can perhaps populate other solver data types here by looking at the typeof ppeDict entries + var.ppeDict[solveKey] = calcVariablePPE(var, method=MeanMaxPPE, solveKey=solveKey) return var end diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index 07f87a55b..565ceddde 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -377,7 +377,7 @@ function updateFullVertData!(fgl::AbstractDFG, if updateMAPest # set PPE in dest from values in srcv # TODO must work for all keys involved - getEstimates(dest)[:default] = getEstimates(srcv)[:default] + getVariablePPEs(dest)[:default] = getVariablePPEs(srcv)[:default] end else # assuming nothing to be done diff --git a/src/IncrementalInference.jl b/src/IncrementalInference.jl index b804bb1de..2306c2950 100644 --- a/src/IncrementalInference.jl +++ b/src/IncrementalInference.jl @@ -48,7 +48,7 @@ import Random: rand, rand! import KernelDensityEstimate: getBW import ApproxManifoldProducts: kde!, manikde! import DistributedFactorGraphs: addVariable!, addFactor!, ls, lsf, isInitialized, hasOrphans, compare, compareAllSpecial -import DistributedFactorGraphs: getEstimates +# import DistributedFactorGraphs: getEstimates # missing exports import DistributedFactorGraphs: PackedFunctionNodeData, FunctionNodeData diff --git a/test/testCompareVariablesFactors.jl b/test/testCompareVariablesFactors.jl index d99e5487c..85efd099e 100644 --- a/test/testCompareVariablesFactors.jl +++ b/test/testCompareVariablesFactors.jl @@ -53,7 +53,7 @@ x1b = getVariable(fg2, :x0) ensureAllInitialized!(fg2) -@test compareSimilarVariables(fg, fg2, skipsamples=true, skip=Symbol[:initialized;:inferdim;:estimateDict]) +@test compareSimilarVariables(fg, fg2, skipsamples=true, skip=Symbol[:initialized;:inferdim;:ppeDict]) # fg2 has been solved, so it should fail on the estimate dictionary @test !compareSimilarVariables(fg, fg2, skipsamples=true, skip=Symbol[:initialized;:inferdim]) @@ -63,7 +63,7 @@ tree = wipeBuildNewTree!(fg2) @test !compareSimilarFactors(fg, fg2, skipsamples=true, skipcompute=false) -@test compareFactorGraphs(fg, fg2, skipsamples=true, skipcompute=true, skip=[:initialized;:inferdim;:estimateDict]) +@test compareFactorGraphs(fg, fg2, skipsamples=true, skipcompute=true, skip=[:initialized;:inferdim;:ppeDict]) end diff --git a/test/testSolveSetPPE.jl b/test/testSolveSetPPE.jl index 65278d9f2..f43aeb16c 100644 --- a/test/testSolveSetPPE.jl +++ b/test/testSolveSetPPE.jl @@ -4,7 +4,6 @@ using Test using IncrementalInference using DistributedFactorGraphs - @testset "test PPE update during solve" begin fg = generateCanonicalFG_Kaess(graphinit=true) @@ -16,7 +15,7 @@ vars = getVariableIds(fg) # fetch values before solve before = Dict() for vs in vars - before[vs] = getVariablePPE(getVariable(fg, vs)) + before[vs] = getVariablePPE(getVariable(fg, vs)) |> getSuggestedPPE end # do the solve @@ -34,7 +33,7 @@ solveTree!(fg) after = Dict() for vs in vars - after[vs] = getVariablePPE(getVariable(fg, vs)) + after[vs] = getVariablePPE(getVariable(fg, vs)) |> getSuggestedPPE end # before and after should be noticably different, because first inferred values have been found @@ -48,7 +47,7 @@ end force = Dict() for vs in vars setVariablePosteriorEstimates!(fg, vs) - force[vs] = getVariablePPE(getVariable(fg, vs)) + force[vs] = getVariablePPE(getVariable(fg, vs)) |> getSuggestedPPE # these need to be close to the same as after errd = norm(force[vs] - after[vs]) # @show vs, errd From 323bc172ad09549377a2a092f3a42fb4130fcfb9 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:12:51 -0500 Subject: [PATCH 53/57] drop MAPest for updatePPE --- src/FactorGraphTypes.jl | 4 ++-- src/SolveTree01.jl | 2 +- src/SubGraphFunctions.jl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FactorGraphTypes.jl b/src/FactorGraphTypes.jl index 565ceddde..90eff8e97 100644 --- a/src/FactorGraphTypes.jl +++ b/src/FactorGraphTypes.jl @@ -357,7 +357,7 @@ end # excessive function, needs refactoring function updateFullVertData!(fgl::AbstractDFG, srcv::DFGNode; - updateMAPest::Bool=false ) + updatePPE::Bool=false ) # @warn "Deprecated updateFullVertData!, need alternative" @@ -374,7 +374,7 @@ function updateFullVertData!(fgl::AbstractDFG, lvd.initialized = srcvd.initialized lvd.inferdim = srcvd.inferdim - if updateMAPest + if updatePPE # set PPE in dest from values in srcv # TODO must work for all keys involved getVariablePPEs(dest)[:default] = getVariablePPEs(srcv)[:default] diff --git a/src/SolveTree01.jl b/src/SolveTree01.jl index 0b036bd4e..74b405d24 100644 --- a/src/SolveTree01.jl +++ b/src/SolveTree01.jl @@ -886,7 +886,7 @@ function updateFGBT!(fg::G, for (sym, emsg) in drt.IDvals #TODO -- should become an update call updvert = DFG.getVariable(fg, sym) - # TODO -- not sure if deepcopy is required , updateMAPest=true) + # TODO -- not sure if deepcopy is required , updatePPE=true) @info "updateFGBT, DownReturnBPType, sym=$sym, current inferdim val=$(getVariableInferredDim(updvert))" setValKDE!(updvert, deepcopy(emsg) ) updvert = DFG.getVariable(fg, sym) diff --git a/src/SubGraphFunctions.jl b/src/SubGraphFunctions.jl index 0cbb94501..1c4f7291d 100644 --- a/src/SubGraphFunctions.jl +++ b/src/SubGraphFunctions.jl @@ -24,7 +24,7 @@ function transferUpdateSubGraph!(dest::AbstractDFG, pp = getKDE(vari) rc2 = size(getPoints(pp)) @info "sym=$sym, mem size of val=$rc and $(rc2)" - updateFullVertData!(dest, vari, updateMAPest=true) + updateFullVertData!(dest, vari, updatePPE=true) end end nothing From e7ebefbdcd09cdd417ad82fa1186dd69e06da691 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:30:22 -0500 Subject: [PATCH 54/57] more specific updatePPE and tests --- src/CliqStateMachine.jl | 6 +++--- src/SubGraphFunctions.jl | 5 +++-- test/testBasicGraphs.jl | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/CliqStateMachine.jl b/src/CliqStateMachine.jl index 3c07c156d..49bfb0343 100644 --- a/src/CliqStateMachine.jl +++ b/src/CliqStateMachine.jl @@ -126,7 +126,7 @@ function doCliqDownSolve_StateMachine(csmc::CliqStateMachineContainer) # transfer results to main factor graph frsyms = getCliqFrontalVarIds(csmc.cliq) infocsm(csmc, "11, finishingCliq -- going for transferUpdateSubGraph! on $frsyms") - transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms, csmc.logger) + transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms, csmc.logger, updatePPE=true) # setCliqStatus!(csmc.cliq, :downsolved) # should be a notify infocsm(csmc, "11, doCliqDownSolve_StateMachine -- before notifyCliqDownInitStatus!") @@ -201,7 +201,7 @@ function determineCliqIfDownSolve_StateMachine(csmc::CliqStateMachineContainer) # Calculate estimates map(sym -> setVariablePosteriorEstimates!(csmc.cliqSubFg, sym), frsyms) # Transfer to parent graph - transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms) + transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms, updatePPE=true) notifyCliqDownInitStatus!(csmc.cliq, :downsolved, logger=csmc.logger) @@ -227,7 +227,7 @@ function finishCliqSolveCheck_StateMachine(csmc::CliqStateMachineContainer) frsyms = getCliqFrontalVarIds(csmc.cliq) infocsm(csmc, "9, finishingCliq -- going for transferUpdateSubGraph! on $frsyms") # TODO what about down solve?? - transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms, csmc.logger) + transferUpdateSubGraph!(csmc.dfg, csmc.cliqSubFg, frsyms, csmc.logger, updatePPE=false) # remove any solvable upward cached data -- TODO will have to be changed for long down partial chains # assuming maximally complte up solved cliq at this point diff --git a/src/SubGraphFunctions.jl b/src/SubGraphFunctions.jl index 1c4f7291d..0ebc42f7b 100644 --- a/src/SubGraphFunctions.jl +++ b/src/SubGraphFunctions.jl @@ -10,7 +10,8 @@ Notes function transferUpdateSubGraph!(dest::AbstractDFG, src::AbstractDFG, syms::Vector{Symbol}=union(ls(src)...), - logger=ConsoleLogger() ) + logger=ConsoleLogger(); + updatePPE::Bool=true ) # with_logger(logger) do @info "transferUpdateSubGraph! -- syms=$syms" @@ -24,7 +25,7 @@ function transferUpdateSubGraph!(dest::AbstractDFG, pp = getKDE(vari) rc2 = size(getPoints(pp)) @info "sym=$sym, mem size of val=$rc and $(rc2)" - updateFullVertData!(dest, vari, updatePPE=true) + updateFullVertData!(dest, vari, updatePPE=updatePPE) end end nothing diff --git a/test/testBasicGraphs.jl b/test/testBasicGraphs.jl index 29a82a1b5..35f131632 100644 --- a/test/testBasicGraphs.jl +++ b/test/testBasicGraphs.jl @@ -150,8 +150,8 @@ tree, smt, hist = solveTree!(fg) @test abs((getKDE(fg, :x0) |> getKDEMean)[1]+1) < 0.5 @test abs((getKDE(fg, :x1) |> getKDEMean)[1]-1) < 0.5 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 1.8 -@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 1.8 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x0))[1,:] ) < 2.0 +@test 0.4 < Statistics.cov( getPoints(getKDE(fg, :x1))[1,:] ) < 2.0 end From 47f5b08e6575d550d17109fdacea623fc785bda2 Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:35:34 -0500 Subject: [PATCH 55/57] julia 1.0 does not have splitpath --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 9d2ebde4a..af8ce4ed6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -92,7 +92,7 @@ include("testAnalysisTools.jl") @testset "saving to and loading from FileDFG" begin saveFolder = "/tmp/dfg_test" - saveDFG(fg, saveFolder) + saveDFG(fg, saveFolder, compress= VERSION == v"1.0" ? :none : :gzip) retDFG = GraphsDFG{SolverParams}(params=SolverParams()) retDFG = loadDFG(saveFolder, IncrementalInference, retDFG) @test symdiff(ls(fg), ls(retDFG)) == [] From 2611407e755ad10adb556f883217d0bd03fa806c Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:40:26 -0500 Subject: [PATCH 56/57] fix version test --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index af8ce4ed6..566ba9a47 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -92,7 +92,7 @@ include("testAnalysisTools.jl") @testset "saving to and loading from FileDFG" begin saveFolder = "/tmp/dfg_test" - saveDFG(fg, saveFolder, compress= VERSION == v"1.0" ? :none : :gzip) + saveDFG(fg, saveFolder, compress= VERSION < v"1.1" ? :none : :gzip) retDFG = GraphsDFG{SolverParams}(params=SolverParams()) retDFG = loadDFG(saveFolder, IncrementalInference, retDFG) @test symdiff(ls(fg), ls(retDFG)) == [] From 3a33bd62fcabe1fa63907e158f06767d01b7ec4f Mon Sep 17 00:00:00 2001 From: dehann Date: Fri, 17 Jan 2020 13:58:13 -0500 Subject: [PATCH 57/57] remove old JLD and splitpath --- test/runtests.jl | 13 ++++---- test/testExpandedJLD.jl | 74 ----------------------------------------- 2 files changed, 7 insertions(+), 80 deletions(-) delete mode 100644 test/testExpandedJLD.jl diff --git a/test/runtests.jl b/test/runtests.jl index 566ba9a47..0daf17f29 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -92,15 +92,16 @@ include("testAnalysisTools.jl") @testset "saving to and loading from FileDFG" begin saveFolder = "/tmp/dfg_test" + # VERSION above 1.0.x hack required since Julia 1.0 does not seem to have function `splitpath` saveDFG(fg, saveFolder, compress= VERSION < v"1.1" ? :none : :gzip) - retDFG = GraphsDFG{SolverParams}(params=SolverParams()) - retDFG = loadDFG(saveFolder, IncrementalInference, retDFG) - @test symdiff(ls(fg), ls(retDFG)) == [] - @test symdiff(lsf(fg), lsf(retDFG)) == [] + retDFG = LightDFG{SolverParams}(params=SolverParams()) + if v"1.1" <= VERSION + retDFG = loadDFG(saveFolder, IncrementalInference, retDFG) + @test symdiff(ls(fg), ls(retDFG)) == [] + @test symdiff(lsf(fg), lsf(retDFG)) == [] + end end -@warn "must return testExpandedJLD.jl to testing -- currently skipped since jld2 files cannot be loaded." -# include("testExpandedJLD.jl") # dont run test on ARM, as per issue #527 if Base.Sys.ARCH in [:x86_64;] diff --git a/test/testExpandedJLD.jl b/test/testExpandedJLD.jl deleted file mode 100644 index 79539a7a3..000000000 --- a/test/testExpandedJLD.jl +++ /dev/null @@ -1,74 +0,0 @@ -using IncrementalInference -using Test - -# setSerializationNamespace!("Main" => Main) - -@testset "test solve by saving and loading basic jld..." begin - - -fgt = initfg() - -addVariable!(fgt, :x1, ContinuousScalar) -addFactor!(fgt, [:x1], Prior(Normal())) - -addVariable!(fgt, :x2, ContinuousScalar) -addFactor!(fgt, [:x1;:x2], LinearConditional(Normal(10,1))) - -savejld(fgt) -# savejld(fgt, file=joinpath(Pkg.dir("IncrementalInference"),"test","testdata","compatibility_test_fg.jld")) -fgl, = loadjld() - -fct = solverData(getFactor(fgt, :x1x2f1)).fnc.cpt[1].factormetadata -fcl = solverData(getFactor(fgl, :x1x2f1)).fnc.cpt[1].factormetadata - -@test fct.solvefor == fcl.solvefor -@test length(fct.variableuserdata) == length(fcl.variableuserdata) - -batchSolve!(fgt) -batchSolve!(fgl) - -# test again after solve -@test fct.solvefor == fcl.solvefor -@test length(fct.variableuserdata) == length(fcl.variableuserdata) - -# save load and repeat tests -savejld(fgt, file="tempfg.jld2") -fgl, = loadjld(file="tempfg.jld2") - -Base.rm("tempfg.jld2") - -fct = solverData(getFactor(fgt, :x1x2f1)).fnc.cpt[1].factormetadata -fcl = solverData(getFactor(fgl, :x1x2f1)).fnc.cpt[1].factormetadata - -# @test fct.solvefor == fcl.solvefor # defaults to :null during load -@test length(fct.variableuserdata) == length(fcl.variableuserdata) - - -end - - - -@testset "test backwards compatibility of loadjld from previous versions of IIF (from an existing test data file)..." begin - -filename = joinpath(dirname(pathof(IncrementalInference)), "..", "test","testdata","compatibility_test_fg.jld2") -# savejld(fgt, file=filename) # when changing to a new compat test file (human required) -fgprev, = loadjld(file=filename ) - -fc = solverData(getFactor(fgprev, :x1x2f1)) -@test length(fc.fnc.cpt[1].factormetadata.variableuserdata) == 2 -@test fc.fnc.cpt[1].factormetadata.solvefor == :null - -# batchSolve!(fgprev) -solveTree!(fgprev) - - -end - - - - - - - - -#