new DecisionTree constructor and methods that takes an op to convert from one type to another

# Conflicts:
#	gtsam/hybrid/DCMixtureFactor.h
release/4.3a0
Varun Agrawal 2021-12-29 15:15:19 -05:00 committed by Frank Dellaert
parent 8b5d93ad37
commit bb6e489c37
2 changed files with 58 additions and 1 deletions

View File

@ -457,6 +457,14 @@ namespace gtsam {
root_ = convert(other.root_, map, op);
}
/*********************************************************************************/
template <typename L, typename Y>
template <typename X>
DecisionTree<L, Y>::DecisionTree(const DecisionTree<L, X>& other,
std::function<Y(const X&)> op) {
root_ = convert(other.root_, op);
}
/*********************************************************************************/
// Called by two constructors above.
// Takes a label and a corresponding range of decision trees, and creates a new
@ -602,6 +610,38 @@ namespace gtsam {
return LY::compose(functions.begin(), functions.end(), newLabel);
}
/*********************************************************************************/
template<typename L, typename Y>
template<typename X>
typename DecisionTree<L, Y>::NodePtr DecisionTree<L, Y>::convert(
const typename DecisionTree<L, X>::NodePtr& f,
std::function<Y(const X&)> op) {
typedef DecisionTree<L, X> LX;
typedef typename LX::Leaf LXLeaf;
typedef typename LX::Choice LXChoice;
typedef typename LX::NodePtr LXNodePtr;
typedef DecisionTree<L, Y> LY;
// ugliness below because apparently we can't have templated virtual functions
// If leaf, apply unary conversion "op" and create a unique leaf
const LXLeaf* leaf = dynamic_cast<const LXLeaf*> (f.get());
if (leaf) return NodePtr(new Leaf(op(leaf->constant())));
// Check if Choice
boost::shared_ptr<const LXChoice> choice = boost::dynamic_pointer_cast<const LXChoice> (f);
if (!choice) throw std::invalid_argument(
"DecisionTree::Convert: Invalid NodePtr");
// put together via Shannon expansion otherwise not sorted.
std::vector<LY> functions;
for(const LXNodePtr& branch: choice->branches()) {
LY converted(convert<X>(branch, op));
functions += converted;
}
return LY::compose(functions.begin(), functions.end(), choice->label());
}
/*********************************************************************************/
template<typename L, typename Y>
bool DecisionTree<L, Y>::equals(const DecisionTree& other, double tol) const {

View File

@ -119,7 +119,12 @@ namespace gtsam {
convert(const typename DecisionTree<M, X>::NodePtr& f, const std::map<M,
L>& map, std::function<Y(const X&)> op);
public:
/** Convert only node to a different type */
template <typename X>
NodePtr convert(const typename DecisionTree<L, X>::NodePtr& f,
const std::function<Y(const X&)> op);
public:
/// @name Standard Constructors
/// @{
@ -155,6 +160,11 @@ namespace gtsam {
DecisionTree(const DecisionTree<M, X>& other,
const std::map<M, L>& map, std::function<Y(const X&)> op);
/** Convert only nodes from a different type */
template <typename X>
DecisionTree(const DecisionTree<L, X>& other,
std::function<Y(const X&)> op);
/// @}
/// @name Testable
/// @{
@ -231,12 +241,19 @@ namespace gtsam {
/** free versions of apply */
//TODO(Varun) where are these templates Y, L and not L, Y?
template<typename Y, typename L>
DecisionTree<L, Y> apply(const DecisionTree<L, Y>& f,
const typename DecisionTree<L, Y>::Unary& op) {
return f.apply(op);
}
template<typename Y, typename L, typename X>
DecisionTree<L, Y> apply(const DecisionTree<L, Y>& f,
const std::function<Y(const X&)>& op) {
return f.apply(op);
}
template<typename Y, typename L>
DecisionTree<L, Y> apply(const DecisionTree<L, Y>& f,
const DecisionTree<L, Y>& g,