indii/ml/aux/KDTree.hpp

00001 #ifndef INDII_ML_AUX_KDTREE_HPP
00002 #define INDII_ML_AUX_KDTREE_HPP
00003 
00004 #include "PartitionTree.hpp"
00005 #include "KDTreeNode.hpp"
00006 #include "MedianPartitioner.hpp"
00007 
00008 #include "boost/serialization/split_member.hpp"
00009 
00010 #include <vector>
00011 
00012 namespace indii {
00013   namespace ml {
00014     namespace aux {
00015 /**
00016  * \f$kd\f$ (k-dimensional) tree over a DiracMixturePdf.
00017  *
00018  * @author Lawrence Murray <lawrence@indii.org>
00019  * @version $Rev: 584 $
00020  * @date $Date: 2008-12-15 17:26:36 +0000 (Mon, 15 Dec 2008) $
00021  *
00022  * @param ST Space partitioner type, derived from Partitioner.
00023  *
00024  * @section KDTree_references References
00025  *
00026  * @anchor Gray2001
00027  * Gray, A. G. & Moore, A. W. `N-Body' Problems in Statistical
00028  * Learning. <i>Advances in Neural Information Processing Systems</i>,
00029  * <b>2001</b>, <i>13</i>.
00030  */
00031 template <class ST = MedianPartitioner>
00032 class KDTree : public PartitionTree {
00033 public:
00034   /**
00035    * Default constructor.
00036    *
00037    * This should generally only be used when the object is to be
00038    * restored from a serialization.
00039    */
00040   KDTree();
00041 
00042   /**
00043    * Constructor.
00044    *
00045    * @param p Weighted sample set from which to build the tree.
00046    */
00047   KDTree(DiracMixturePdf* p);
00048 
00049   /**
00050    * Copy constructor.
00051    */
00052   KDTree(const KDTree<ST>& o);
00053 
00054   /**
00055    * Destructor.
00056    */
00057   virtual ~KDTree();
00058 
00059   virtual PartitionTree* clone();
00060 
00061   /**
00062    * Assignment operator.
00063    */
00064   KDTree<ST>& operator=(const KDTree<ST>& o);
00065 
00066   virtual PartitionTreeNode* getRoot();
00067 
00068   virtual void setRoot(PartitionTreeNode* root);
00069 
00070 private:
00071   /**
00072    * Root node of the tree.
00073    */
00074   KDTreeNode* root;
00075 
00076   /**
00077    * Build \f$kd\f$ tree node.
00078    *
00079    * @param p Weighted sample set.
00080    * @param is Indices of the subset of components in p over which to build
00081    * the node.
00082    * @param depth Depth of the node in the tree. Zero for the root node.
00083    * 
00084    * @return The node. Caller has ownership.
00085    */
00086   static KDTreeNode* build(DiracMixturePdf* p,
00087       const std::vector<unsigned int>& is, const unsigned int depth = 0);
00088 
00089   /**
00090    * Serialize.
00091    */
00092   template<class Archive>
00093   void save(Archive& ar, const unsigned int version) const;
00094 
00095   /**
00096    * Restore from serialization.
00097    */
00098   template<class Archive>
00099   void load(Archive& ar, const unsigned int version);
00100 
00101   /*
00102    * Boost.Serialization requirements.
00103    */
00104   BOOST_SERIALIZATION_SPLIT_MEMBER()
00105   friend class boost::serialization::access;
00106 
00107 };
00108    
00109     }
00110   }
00111 }
00112 
00113 #include "boost/serialization/base_object.hpp"
00114 
00115 template<class ST>
00116 indii::ml::aux::KDTree<ST>::KDTree() : root(NULL) {
00117   //
00118 }
00119 
00120 template<class ST>
00121 indii::ml::aux::KDTree<ST>::KDTree(DiracMixturePdf* p) : PartitionTree(p) {
00122   unsigned int i;
00123   std::vector<unsigned int> is(p->getSize());
00124 
00125   for (i = 0; i < is.size(); i++) {
00126     is[i] = i;
00127   }
00128 
00129   if (is.size() > 0) {  
00130     root = build(p, is);
00131   } else {
00132     root = NULL;
00133   }
00134 }
00135 
00136 template<class ST>
00137 indii::ml::aux::KDTree<ST>::KDTree(const KDTree<ST>& o) :
00138     PartitionTree(o) {
00139   if (o.root == NULL) {
00140     root = NULL;
00141   } else {
00142     root = dynamic_cast<KDTreeNode*>(o.root->clone());
00143   }
00144 }
00145 
00146 template<class ST>
00147 indii::ml::aux::KDTree<ST>::~KDTree() {
00148   delete root;
00149 }
00150 
00151 template<class ST>
00152 indii::ml::aux::KDTree<ST>& indii::ml::aux::KDTree<ST>::operator=(
00153     const KDTree<ST>& o) {
00154   PartitionTree::operator=(o);
00155 
00156   delete root;
00157   if (o.root == NULL) {
00158     root = NULL;
00159   } else {
00160     root = dynamic_cast<KDTreeNode*>(o.root->clone());
00161   }
00162   
00163   return *this;
00164 }
00165 
00166 template<class ST>
00167 indii::ml::aux::PartitionTree* indii::ml::aux::KDTree<ST>::clone() {
00168   return new KDTree<ST>(*this);
00169 }
00170 
00171 template<class ST>
00172 inline indii::ml::aux::PartitionTreeNode*
00173     indii::ml::aux::KDTree<ST>::getRoot() {
00174   return root;
00175 }
00176 
00177 template<class ST>
00178 void indii::ml::aux::KDTree<ST>::setRoot(PartitionTreeNode* root) {
00179   this->root = dynamic_cast<KDTreeNode*>(root);
00180 }
00181 
00182 template<class ST>
00183 indii::ml::aux::KDTreeNode* indii::ml::aux::KDTree<ST>::build(
00184     DiracMixturePdf* p, const std::vector<unsigned int>& is,
00185     const unsigned int depth) {
00186   /* pre-condition */
00187   assert (is.size() > 0);
00188 
00189   KDTreeNode* result;
00190   unsigned int i;
00191   
00192   if (is.size() == 1) {
00193     /* leaf node */
00194     result = new KDTreeNode(p, is.front(), depth);
00195   } else {
00196     /* internal node */
00197     ST partitioner;
00198 
00199     if (partitioner.init(p, is)) {
00200       std::vector<unsigned int> ls, rs; // indices of left, right components
00201       KDTreeNode *left, *right; // child nodes
00202 
00203       ls.reserve(is.size() / 2);
00204       rs.reserve(is.size() / 2);
00205       
00206       for (i = 0; i < is.size(); i++) {
00207         if (partitioner.assign(p->get(is[i])) == Partitioner::LEFT) {
00208           ls.push_back(is[i]);
00209         } else {
00210           rs.push_back(is[i]);
00211         }
00212       }
00213 
00214       if (ls.size() == 0) {
00215         /* degenerate case, prune node */
00216         result = new KDTreeNode(p, rs, depth);
00217       } else if (rs.size() == 0) {
00218         /* degenerate case, prune node */
00219         result = new KDTreeNode(p, ls, depth);        
00220       } else {
00221         /* internal node */
00222         left = build(p, ls, depth + 1);
00223         right = build(p, rs, depth + 1);
00224       
00225         result = new KDTreeNode(left, right, depth);
00226       }
00227     } else {
00228       /* Degenerate case, usually occurs when all points are identical or
00229          one has negligible weight, so that they cannot be partitioned
00230          spatially. Put them all into one prune node... */
00231       result = new KDTreeNode(p, is, depth);
00232     }
00233   }
00234 
00235   return result;
00236 }
00237 
00238 template<class ST>
00239 template<class Archive>
00240 void indii::ml::aux::KDTree<ST>::save(Archive& ar,
00241     const unsigned int version) const {
00242   ar & boost::serialization::base_object<PartitionTree>(*this);
00243 
00244   const bool haveRoot = (root != NULL);
00245   ar & haveRoot;
00246   if (haveRoot) {
00247     ar & root;
00248   }
00249 }
00250 
00251 template<class ST>
00252 template<class Archive>
00253 void indii::ml::aux::KDTree<ST>::load(Archive& ar,
00254     const unsigned int version) {  
00255   bool haveRoot = false;
00256   
00257   if (root != NULL) {
00258     delete root;
00259     root = NULL;
00260   }
00261   
00262   ar & boost::serialization::base_object<PartitionTree>(*this);
00263   ar & haveRoot;
00264   if (haveRoot) {
00265     ar & root;
00266   }
00267 }
00268 
00269 #endif
00270 

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3