indii/ml/aux/kde.hpp

Go to the documentation of this file.
00001 #ifndef INDII_ML_AUX_KDE_HPP
00002 #define INDII_ML_AUX_KDE_HPP
00003 
00004 #include "PartitionTree.hpp"
00005 
00006 /**
00007  * @file kde.hpp
00008  *
00009  * Provides convenience methods for working with kernel density
00010  * approximations.
00011  */
00012 
00013 namespace indii {
00014   namespace ml {
00015     namespace aux {
00016 
00017 /**
00018  * Calculate \f$h_{opt}\f$.
00019  *
00020  * @param N Number of dimensions.
00021  * @param P Number of samples.
00022  *
00023  * Note:
00024  *
00025  * \f[
00026  * h_{opt} = \left[\frac{4}{(N+2)P}\right]^{\frac{1}{N+4}}\,,
00027  * \f]
00028  *
00029  * this being the optimal bandwidth for a kernel density estimate
00030  * over \f$P\f$ samples from a standard \f$N\f$-dimensional Gaussian
00031  * distribution, and Gaussian kernel (@ref Silverman1986
00032  * "Silverman, 1986"). We find this useful as a rule of thumb for
00033  * setting kernel density estimate bandwidths.
00034  *
00035  * @section hopt_references References
00036  *
00037  * @anchor Silverman1986
00038  * Silverman, B.W. <i>Density Estimation for Statistics and Data
00039  * Analysis</i>. Chapman and Hall, <b>1986</b>.
00040  */
00041 double hopt(const unsigned int N, const unsigned int P);
00042 
00043 /**
00044  * Dual-tree kernel density evaluation.
00045  *
00046  * @param NT Norm type.
00047  * @param KT Kernel type.
00048  * @param PT Partition tree type.
00049  *
00050  * @param queryTree Query tree.
00051  * @param targetTree Target tree.
00052  * @param w Weight vector.
00053  * @param N Norm.
00054  * @param K Kernel.
00055  * @param normalise Normalise results.
00056  *
00057  * @return Vector of the density estimates for each of the points in 
00058  * queryTree, ordered according to its underlying data.
00059  */
00060 template <class NT, class KT, class PT>
00061 vector dualTreeDensity(PT& queryTree, PT& targetTree,
00062     const vector& w, const NT& N, const KT& K, const bool normalise = true);
00063       
00064 /**
00065  * Distributed dual-tree kernel density evaluation.
00066  *
00067  * @param NT Norm type.
00068  * @param KT Kernel type.
00069  * @param PT Partition tree type.
00070  *
00071  * @param queryTree Query tree.
00072  * @param targetTree Target tree.
00073  * @param w Weight vector.
00074  * @param N Norm.
00075  * @param K Kernel.
00076  * @param normalise Normalise results.
00077  *
00078  * @return Vector of the density estimates for each of the points in 
00079  * queryTree, ordered according to its underlying data. Note that while
00080  * only the results for the local query components are returned, all
00081  * nodes participate in the evaluation.
00082  *
00083  * Note that queryTree and targetTree should have different underlying
00084  * DiracMixturePdf objects.
00085  */
00086 template <class NT, class KT, class PT>
00087 vector distributedDualTreeDensity(PT& queryTree,
00088     PT& targetTree, const vector& w, const NT& N, const KT& K,
00089     const bool normalise = true);
00090 
00091 /**
00092  * Self-tree kernel density evaluation.
00093  *
00094  * @param NT Norm type.
00095  * @param KT Kernel type.
00096  * @param PT Partition tree type.
00097  *
00098  * @param tree Tree.
00099  * @param w Weight vector.
00100  * @param N Norm.
00101  * @param K Kernel.
00102  * @param normalise Normalise results.
00103  *
00104  * @return Vector of the density estimates for each of the points in 
00105  * queryTree, ordered according to its underlying data.
00106  */
00107 template <class NT, class KT, class PT>
00108 vector selfTreeDensity(PT& tree, const vector& w, const NT& N,
00109     const KT& K, const bool normalise = true);
00110       
00111 /**
00112  * Distributed self-tree kernel density evaluation.
00113  *
00114  * @param NT Norm type.
00115  * @param KT Kernel type.
00116  * @param PT Partition tree type.
00117  *
00118  * @param tree Tree.
00119  * @param w Weight vector.
00120  * @param N Norm.
00121  * @param K Kernel.
00122  * @param normalise Normalise results.
00123  *
00124  * @return Vector of the density estimates for each of the points in 
00125  * queryTree, ordered according to its underlying data. Note that while
00126  * only the results for the local query components are returned, all
00127  * nodes participate in the evaluation.
00128  */
00129 template <class NT, class KT, class PT>
00130 vector distributedSelfTreeDensity(PT& tree, const vector& w,
00131     const NT& N, const KT& K, const bool normalise = true);
00132 
00133 /**
00134  * Dual-tree kernel density evaluation with multiple mixture model
00135  * weights.
00136  *
00137  * @param NT Norm type.
00138  * @param KT Kernel type.
00139  * @param PT Partition tree type.
00140  *
00141  * @param queryTree Query tree.
00142  * @param targetTree Target tree.
00143  * @param ws Weight matrix. Each row gives a weight vector for one mixture
00144  * model.
00145  * @param N Norm.
00146  * @param K Kernel.
00147  * @param normalise Normalise results.
00148  *
00149  * @return Matrix where each row provides the density estimates for each
00150  * of the points in queryTree, ordered according its underlying data, and
00151  * using the weights of the corresponding row in ws. The weights
00152  * underlying queryTree and targetTree are ignored. Optimisations are
00153  * made in the case that the queryTree and targetTree are identical and
00154  * over the same underlying data.
00155  */
00156 template <class NT, class KT, class PT>
00157 matrix dualTreeDensity(PT& queryTree, PT& targetTree,
00158     const matrix& ws, const NT& N, const KT& K, const bool normalise = true);
00159       
00160 /**
00161  * Distributed dual-tree kernel density evaluation with multiple mixture
00162  * model weights.
00163  *
00164  * @param NT Norm type.
00165  * @param KT Kernel type.
00166  * @param PT Partition tree type.
00167  *
00168  * @param queryTree Query tree.
00169  * @param targetTree Target tree.
00170  * @param ws Weight matrix. Each row gives a weight vector for one mixture
00171  * model.
00172  * @param N Norm.
00173  * @param K Kernel.
00174  * @param normalise Normalise results.
00175  *
00176  * @return Matrix where each row provides the density estimates for each
00177  * of the points in queryTree, ordered according its underlying data, and
00178  * using the weights of the corresponding row in ws. The weights
00179  * underlying queryTree and targetTree are ignored.
00180  *
00181  * Note that queryTree and targetTree should have different underlying
00182  * DiracMixturePdf objects.
00183  */
00184 template <class NT, class KT, class PT>
00185 matrix distributedDualTreeDensity(PT& queryTree,
00186     PT& targetTree, const matrix& ws, const NT& N, const KT& K,
00187     const bool normalise = true);
00188 
00189 /**
00190  * Self-tree kernel density evaluation with multiple mixture model
00191  * weights.
00192  *
00193  * @param NT Norm type.
00194  * @param KT Kernel type.
00195  * @param PT Partition tree type.
00196  *
00197  * @param tree Tree.
00198  * @param ws Weight matrix. Each row gives a weight vector for one mixture
00199  * model.
00200  * @param N Norm.
00201  * @param K Kernel.
00202  * @param normalise Normalise results.
00203  *
00204  * @return Matrix where each row provides the density estimates for each
00205  * of the points in queryTree, ordered according its underlying data, and
00206  * using the weights of the corresponding row in ws. The weights underlying
00207  * tree are ignored.
00208  */
00209 template <class NT, class KT, class PT>
00210 matrix selfTreeDensity(PT& tree, const matrix& ws, const NT& N,
00211     const KT& K, const bool normalise = true);
00212       
00213 /**
00214  * Distributed self tree kernel density evaluation with multiple mixture
00215  * model weights.
00216  *
00217  * @param NT Norm type.
00218  * @param KT Kernel type.
00219  * @param PT Partition tree type.
00220  *
00221  * @param tree Tree.
00222  * @param ws Weight matrix. Each row gives a weight vector for one mixture
00223  * model.
00224  * @param N Norm.
00225  * @param K Kernel.
00226  * @param normalise Normalise results.
00227  *
00228  * @return Matrix where each row provides the density estimates for each
00229  * of the points in queryTree, ordered according its underlying data, and
00230  * using the weights of the corresponding row in ws. The weights underlying
00231  * tree are ignored.
00232  */
00233 template <class NT, class KT, class PT>
00234 matrix distributedSelfTreeDensity(PT& tree, const matrix& ws,
00235     const NT& N, const KT& K, const bool normalise = true);
00236 
00237 /**
00238  * Cross-tree kernel density evaluation with multiple mixture model
00239  * weights. Simultaneously performs kernel density estimation of two 
00240  * trees to each other.
00241  *
00242  * @param NT Norm type.
00243  * @param KT Kernel type.
00244  * @param PT Partition tree type.
00245  *
00246  * @param tree1 First tree.
00247  * @param tree2 Second tree.
00248  * @param ws1 Weight matrix for first tree as target. Each row gives a
00249  * weight vector for one mixture model.
00250  * @param ws2 Weight matrix for second tree as target. Each row gives a
00251  * weight vector for one mixture model.
00252  * @param N Norm.
00253  * @param K Kernel.
00254  * @param result1 On return, unnormalised result for first tree as query,
00255  * second as target, is added to this.
00256  * @param result2 On return, unnormalised result for second tree as query,
00257  * first as target, is added to this.
00258  * @param clear Clear result matrices before addition.
00259  * @param normalise Normalise results.
00260  *
00261  * Intended mainly for internal use.
00262  */
00263 template <class NT, class KT, class PT>
00264 void crossTreeDensity(PT& tree1, PT& tree2,
00265     const matrix& ws1, const matrix& ws2, const NT& N, const KT& K,
00266     matrix& result1, matrix& result2, const bool clear = true,
00267     const bool normalise = true);
00268 
00269     }
00270   }
00271 }
00272 
00273 #include "DiracMixturePdf.hpp"
00274 #include "KDTree.hpp"
00275 #include "vector.hpp"
00276 #include "matrix.hpp"
00277 
00278 #include <stack>
00279 
00280 inline double indii::ml::aux::hopt(const unsigned int N,
00281     const unsigned int P) {
00282   return pow(4.0/((N+2)*P), 1.0/(N+4.0));
00283 }
00284 
00285 template <class NT, class KT, class PT>
00286 indii::ml::aux::vector indii::ml::aux::dualTreeDensity(
00287     PT& queryTree, PT& targetTree, const vector& w,
00288     const NT& N, const KT& K, const bool normalise) {
00289   aux::matrix ws(1,w.size());
00290   row(ws,0) = w;
00291   return row(dualTreeDensity(queryTree, targetTree, ws, N, K, normalise), 0);
00292 }
00293 
00294 template <class NT, class KT, class PT>
00295 indii::ml::aux::vector indii::ml::aux::distributedDualTreeDensity(
00296     PT& queryTree, PT& targetTree, const vector& w,
00297     const NT& N, const KT& K, const bool normalise) {
00298   aux::matrix ws(1,w.size());
00299   row(ws,0) = w;
00300   return row(distributedDualTreeDensity(queryTree, targetTree, ws, N, K,
00301       normalise), 0);
00302 }
00303 
00304 template <class NT, class KT, class PT>
00305 indii::ml::aux::vector indii::ml::aux::selfTreeDensity(
00306     PT& tree, const vector& w, const NT& N, const KT& K,
00307     const bool normalise) {
00308   aux::matrix ws(1,w.size());
00309   row(ws,0) = w;
00310   return row(selfTreeDensity(tree, ws, N, K, normalise), 0);
00311 }
00312 
00313 template <class NT, class KT, class PT>
00314 indii::ml::aux::vector indii::ml::aux::distributedSelfTreeDensity(
00315     PT& tree, const vector& w, const NT& N, const KT& K,
00316     const bool normalise) {
00317   aux::matrix ws(1,w.size());
00318   row(ws,0) = w;
00319   return row(distributedSelfTreeDensity(tree, ws, N, K, normalise), 0);
00320 }
00321 
00322 template <class NT, class KT, class PT>
00323 indii::ml::aux::matrix indii::ml::aux::dualTreeDensity(
00324     PT& queryTree, PT& targetTree, const matrix& ws,
00325     const NT& N, const KT& K, const bool normalise) {
00326   /* pre-condition */
00327   assert (ws.size2() == targetTree.getData()->getSize());
00328   assert (queryTree.getData()->getDimensions() ==
00329       targetTree.getData()->getDimensions());
00330   
00331   DiracMixturePdf& q = *queryTree.getData();
00332   DiracMixturePdf& p = *targetTree.getData();
00333   PartitionTreeNode* queryRoot = queryTree.getRoot();
00334   PartitionTreeNode* targetRoot = targetTree.getRoot();
00335 
00336   matrix result(ws.size1(), q.getSize());
00337   result.clear();
00338   
00339   if (queryRoot != NULL && targetRoot != NULL) {
00340     std::stack<PartitionTreeNode*> queryNodes, targetNodes;
00341 
00342     vector x(p.getDimensions());
00343     unsigned int i, j;
00344     double w, d;
00345 
00346     queryNodes.push(queryRoot);
00347     targetNodes.push(targetRoot);
00348     
00349     while (!queryNodes.empty()) {
00350       PartitionTreeNode& queryNode = *queryNodes.top();
00351       queryNodes.pop();
00352       PartitionTreeNode& targetNode = *targetNodes.top();
00353       targetNodes.pop();
00354 
00355       if (queryNode.isLeaf() && targetNode.isLeaf()) {
00356         i = queryNode.getIndex();
00357         j = targetNode.getIndex();
00358         noalias(x) = q.get(i) - p.get(j);
00359         d = K(N(x));
00360         noalias(column(result,i)) += d * column(ws,j);
00361       } else if (queryNode.isLeaf() && targetNode.isPrune()) {
00362         i = queryNode.getIndex();
00363         const std::vector<unsigned int>& js = targetNode.getIndices();
00364         for (j = 0; j < js.size(); j++) {
00365           noalias(x) = q.get(i) - p.get(js[j]);
00366           d = K(N(x));
00367           noalias(column(result,i)) += d * column(ws,js[j]);
00368         }
00369       } else if (queryNode.isPrune() && targetNode.isLeaf()) {
00370         const std::vector<unsigned int>& is = queryNode.getIndices();
00371         j = targetNode.getIndex();
00372         for (i = 0; i < is.size(); i++) {
00373           noalias(x) = q.get(is[i]) - p.get(j);
00374           d = K(N(x));
00375           noalias(column(result,is[i])) += d * column(ws,j);
00376         }
00377       } else if (queryNode.isPrune() && targetNode.isPrune()) {
00378         const std::vector<unsigned int>& is = queryNode.getIndices();
00379         const std::vector<unsigned int>& js = targetNode.getIndices();
00380         for (i = 0; i < is.size(); i++) {
00381           for (j = 0; j < js.size(); j++) {
00382             noalias(x) = q.get(is[i]) - p.get(js[j]);
00383             d = K(N(x));
00384             noalias(column(result,is[i])) += d * column(ws,js[j]);
00385           }
00386         }
00387       } else {
00388         /* should we recurse? */
00389         targetNode.difference(queryNode, x);
00390         if (K(N(x)) > 0.0) {
00391           if (queryNode.isInternal()) {
00392             if (targetNode.isInternal()) {
00393               /* split both query and target nodes */
00394               queryNodes.push(queryNode.getLeft());
00395               targetNodes.push(targetNode.getLeft());
00396           
00397               queryNodes.push(queryNode.getLeft());
00398               targetNodes.push(targetNode.getRight());
00399 
00400               queryNodes.push(queryNode.getRight());
00401               targetNodes.push(targetNode.getLeft());
00402 
00403               queryNodes.push(queryNode.getRight());
00404               targetNodes.push(targetNode.getRight());        
00405             } else {
00406               /* split query node only */
00407               queryNodes.push(queryNode.getLeft());
00408               targetNodes.push(&targetNode);
00409           
00410               queryNodes.push(queryNode.getRight());
00411               targetNodes.push(&targetNode);
00412             }
00413           } else {
00414             /* split target node only */
00415             queryNodes.push(&queryNode);
00416             targetNodes.push(targetNode.getLeft());
00417         
00418             queryNodes.push(&queryNode);
00419             targetNodes.push(targetNode.getRight());
00420           }
00421         }
00422       }
00423     }
00424     
00425     if (normalise) {
00426       result /= p.getTotalWeight();
00427     }
00428   }
00429   
00430   return result;
00431 }
00432 
00433 template <class NT, class KT, class PT>
00434 indii::ml::aux::matrix indii::ml::aux::distributedDualTreeDensity(
00435     PT& queryTree, PT& targetTree, const matrix& ws,
00436     const NT& N, const KT& K, const bool normalise) {
00437   boost::mpi::communicator world;
00438   const unsigned int size = world.size();
00439   unsigned int i;
00440   
00441   matrix result(dualTreeDensity(queryTree, targetTree, ws, N, K, false));
00442   rotate(*queryTree.getData());
00443   rotate(queryTree);
00444   rotate(result);
00445 
00446   for (i = 1; i < size; i++) {
00447     noalias(result) += dualTreeDensity(queryTree, targetTree, ws, N, K,
00448         false);
00449     rotate(*queryTree.getData());
00450     rotate(queryTree);
00451     rotate(result);
00452   }
00453 
00454   if (normalise) {
00455     result /= targetTree.getData()->getDistributedTotalWeight();
00456   }
00457 
00458   return result;
00459 }
00460 
00461 template <class NT, class KT, class PT>
00462 indii::ml::aux::matrix indii::ml::aux::selfTreeDensity(PT& tree,
00463     const matrix& ws, const NT& N, const KT& K, const bool normalise) {
00464   /* pre-condition */
00465   assert (ws.size2() == tree.getData()->getSize());
00466   
00467   DiracMixturePdf& p = *tree.getData();
00468   PartitionTreeNode* root = tree.getRoot();
00469 
00470   matrix result(ws.size1(), p.getSize());
00471   result.clear();
00472   
00473   if (root != NULL) {
00474     std::stack<PartitionTreeNode*> queryNodes, targetNodes;
00475     std::stack<bool> doCrosses; // for query equals target tree optimisations
00476 
00477     vector x(p.getDimensions());
00478     unsigned int i, j;
00479     double w, d;
00480     bool doCross;
00481 
00482     queryNodes.push(root);
00483     targetNodes.push(root);
00484     doCrosses.push(false);
00485     
00486     while (!queryNodes.empty()) {
00487       PartitionTreeNode& queryNode = *queryNodes.top();
00488       queryNodes.pop();
00489       PartitionTreeNode& targetNode = *targetNodes.top();
00490       targetNodes.pop();
00491       doCross = doCrosses.top();
00492       doCrosses.pop();
00493 
00494       if (queryNode.isLeaf() && targetNode.isLeaf()) {
00495         i = queryNode.getIndex();
00496         j = targetNode.getIndex();
00497         noalias(x) = p.get(i) - p.get(j);
00498         d = K(N(x));
00499         if (doCross) {
00500           noalias(column(result,j)) += d * column(ws,i);
00501         }
00502         noalias(column(result,i)) += d * column(ws,j);
00503       } else if (queryNode.isLeaf() && targetNode.isPrune()) {
00504         i = queryNode.getIndex();
00505         const std::vector<unsigned int>& js = targetNode.getIndices();
00506         for (j = 0; j < js.size(); j++) {
00507           noalias(x) = p.get(i) - p.get(js[j]);
00508           d = K(N(x));
00509           if (doCross) {
00510             noalias(column(result,js[j])) += d * column(ws,i);
00511           }
00512           noalias(column(result,i)) += d * column(ws,js[j]);
00513         }
00514       } else if (queryNode.isPrune() && targetNode.isLeaf()) {
00515         const std::vector<unsigned int>& is = queryNode.getIndices();
00516         j = targetNode.getIndex();
00517         for (i = 0; i < is.size(); i++) {
00518           noalias(x) = p.get(is[i]) - p.get(j);
00519           d = K(N(x));
00520           if (doCross) {
00521             noalias(column(result,j)) += d * column(ws,is[i]);
00522           }
00523           noalias(column(result,is[i])) += d * column(ws,j);
00524         }
00525       } else if (queryNode.isPrune() && targetNode.isPrune()) {
00526         const std::vector<unsigned int>& is = queryNode.getIndices();
00527         const std::vector<unsigned int>& js = targetNode.getIndices();
00528         for (i = 0; i < is.size(); i++) {
00529           for (j = 0; j < js.size(); j++) {
00530             noalias(x) = p.get(is[i]) - p.get(js[j]);
00531             d = K(N(x));
00532             if (doCross) {
00533               noalias(column(result,js[j])) += d * column(ws,is[i]);
00534             }
00535             noalias(column(result,is[i])) += d * column(ws,js[j]);
00536           }
00537         }
00538       } else {
00539         /* should we recurse? */
00540         targetNode.difference(queryNode, x);
00541         if (K(N(x)) > 0.0) {
00542           if (queryNode.isInternal()) {
00543             if (targetNode.isInternal()) {
00544               /* split both query and target nodes */
00545               queryNodes.push(queryNode.getLeft());
00546               targetNodes.push(targetNode.getLeft());
00547               doCrosses.push(doCross);
00548           
00549               queryNodes.push(queryNode.getLeft());
00550               targetNodes.push(targetNode.getRight());
00551               if (&queryNode == &targetNode) {
00552                 /* symmetric, so just double left-right evaluation */
00553                 doCrosses.push(true);
00554               } else {
00555                 /* asymmetric, so evaluate right-left separately */
00556                 doCrosses.push(doCross);
00557 
00558                 queryNodes.push(queryNode.getRight());
00559                 targetNodes.push(targetNode.getLeft());
00560                 doCrosses.push(doCross);
00561               }
00562               
00563               queryNodes.push(queryNode.getRight());
00564               targetNodes.push(targetNode.getRight());        
00565               doCrosses.push(doCross);
00566             } else {
00567               /* split query node only */
00568               queryNodes.push(queryNode.getLeft());
00569               targetNodes.push(&targetNode);
00570               doCrosses.push(doCross);
00571           
00572               queryNodes.push(queryNode.getRight());
00573               targetNodes.push(&targetNode);
00574               doCrosses.push(doCross);
00575             }
00576           } else {
00577             /* split target node only */
00578             queryNodes.push(&queryNode);
00579             targetNodes.push(targetNode.getLeft());
00580             doCrosses.push(doCross);
00581         
00582             queryNodes.push(&queryNode);
00583             targetNodes.push(targetNode.getRight());
00584             doCrosses.push(doCross);
00585           }
00586         }
00587       }
00588     }
00589     
00590     if (normalise) {
00591       result /= p.getTotalWeight();
00592     }
00593   }
00594   
00595   return result;
00596 }
00597 
00598 template <class NT, class KT, class PT>
00599 indii::ml::aux::matrix indii::ml::aux::distributedSelfTreeDensity(
00600     PT& tree, const matrix& ws, const NT& N, const KT& K,
00601     const bool normalise) {
00602   boost::mpi::communicator world;
00603   const unsigned int size = world.size();
00604   
00605   matrix result(selfTreeDensity(tree, ws, N, K, false));
00606   
00607   if (size > 1) {
00608     /* cross densities */
00609     unsigned int crosses = (size - 1) / 2;
00610     bool leftover = (size - 1) % 2 > 0;
00611     unsigned int i;
00612   
00613     matrix ws2(ws);
00614     matrix result2(result.size1(), result.size2());
00615     result2.clear();
00616   
00617     PT* tree2 = dynamic_cast<PT*>(tree.clone());
00618     DiracMixturePdf q(*tree.getData());
00619     tree2->setData(&q);
00620     
00621     for (i = 0; i < crosses; i++) {
00622       rotate(*tree2->getData());
00623       rotate(*tree2);
00624       rotate(result2);
00625       rotate(ws2);
00626       crossTreeDensity(tree, *tree2, ws, ws2, N, K, result, result2,
00627           false, false);
00628     }
00629 
00630     if (leftover) {
00631       rotate(*tree2->getData());
00632       rotate(*tree2);
00633       rotate(ws2);
00634       noalias(result) += dualTreeDensity(tree, *tree2, ws2, N, K, false);
00635     }
00636 
00637     /* return results to original node */
00638     rotate(result2, size - i);
00639     noalias(result) += result2;
00640 
00641     delete tree2;
00642   }
00643 
00644   if (normalise) {
00645     result /= tree.getData()->getDistributedTotalWeight();
00646   }
00647 
00648   return result;
00649 }
00650 
00651 template <class NT, class KT, class PT>
00652 void indii::ml::aux::crossTreeDensity(
00653     PT& tree1, PT& tree2, const matrix& ws1,
00654     const matrix& ws2, const NT& N, const KT& K, matrix& result1,
00655     matrix& result2, const bool clear, const bool normalise) {
00656   /* pre-condition */
00657   assert (ws1.size2() == tree1.getData()->getSize());
00658   assert (ws2.size2() == tree2.getData()->getSize());
00659   assert (result1.size2() == tree1.getData()->getSize());
00660   assert (result2.size2() == tree2.getData()->getSize());
00661   assert (result1.size1() == ws1.size1());
00662   assert (result2.size1() == ws2.size1());
00663   assert (tree1.getData()->getDimensions() ==
00664       tree2.getData()->getDimensions());
00665   
00666   DiracMixturePdf& p1 = *tree1.getData();
00667   DiracMixturePdf& p2 = *tree2.getData();
00668   PartitionTreeNode* root1 = tree1.getRoot();
00669   PartitionTreeNode* root2 = tree2.getRoot();
00670 
00671   if (clear) {
00672     result1.clear();
00673     result2.clear();
00674   }
00675   
00676   if (root1 != NULL && root2 != NULL) {
00677     std::stack<PartitionTreeNode*> nodes1, nodes2;
00678 
00679     vector x(p1.getDimensions());
00680     unsigned int i, j;
00681     double w, d;
00682 
00683     nodes1.push(root1);
00684     nodes2.push(root2);
00685     
00686     while (!nodes1.empty()) {
00687       PartitionTreeNode& node1 = *nodes1.top();
00688       nodes1.pop();
00689       PartitionTreeNode& node2 = *nodes2.top();
00690       nodes2.pop();
00691 
00692       if (node1.isLeaf() && node2.isLeaf()) {
00693         i = node1.getIndex();
00694         j = node2.getIndex();
00695         noalias(x) = p1.get(i) - p2.get(j);
00696         d = K(N(x));
00697         noalias(column(result1,i)) += d * column(ws2,j);
00698         noalias(column(result2,j)) += d * column(ws1,i);
00699       } else if (node1.isLeaf() && node2.isPrune()) {
00700         i = node1.getIndex();
00701         const std::vector<unsigned int>& js = node2.getIndices();
00702         for (j = 0; j < js.size(); j++) {
00703           noalias(x) = p1.get(i) - p2.get(js[j]);
00704           d = K(N(x));
00705           noalias(column(result1,i)) += d * column(ws2,js[j]);
00706           noalias(column(result2,js[j])) += d * column(ws1,i);
00707         }
00708       } else if (node1.isPrune() && node2.isLeaf()) {
00709         const std::vector<unsigned int>& is = node1.getIndices();
00710         j = node2.getIndex();
00711         for (i = 0; i < is.size(); i++) {
00712           noalias(x) = p1.get(is[i]) - p2.get(j);
00713           d = K(N(x));
00714           noalias(column(result1,is[i])) += d * column(ws2,j);
00715           noalias(column(result2,j)) += d * column(ws1,is[i]);
00716         }
00717       } else if (node1.isPrune() && node2.isPrune()) {
00718         const std::vector<unsigned int>& is = node1.getIndices();
00719         const std::vector<unsigned int>& js = node2.getIndices();
00720         for (i = 0; i < is.size(); i++) {
00721           for (j = 0; j < js.size(); j++) {
00722             noalias(x) = p1.get(is[i]) - p2.get(js[j]);
00723             d = K(N(x));
00724             noalias(column(result1,is[i])) += d * column(ws2,js[j]);
00725             noalias(column(result2,js[j])) += d * column(ws1,is[i]);
00726           }
00727         }
00728       } else {
00729         /* should we recurse? */
00730         node2.difference(node1, x);
00731         if (K(N(x)) > 0.0) {
00732           if (node1.isInternal()) {
00733             if (node2.isInternal()) {
00734               /* split both query and target nodes */
00735               nodes1.push(node1.getLeft());
00736               nodes2.push(node2.getLeft());
00737           
00738               nodes1.push(node1.getLeft());
00739               nodes2.push(node2.getRight());
00740 
00741               nodes1.push(node1.getRight());
00742               nodes2.push(node2.getLeft());
00743               
00744               nodes1.push(node1.getRight());
00745               nodes2.push(node2.getRight());        
00746             } else {
00747               /* split query node only */
00748               nodes1.push(node1.getLeft());
00749               nodes2.push(&node2);
00750           
00751               nodes1.push(node1.getRight());
00752               nodes2.push(&node2);
00753             }
00754           } else {
00755             /* split target node only */
00756             nodes1.push(&node1);
00757             nodes2.push(node2.getLeft());
00758         
00759             nodes1.push(&node1);
00760             nodes2.push(node2.getRight());
00761           }
00762         }
00763       }
00764     }
00765     
00766     if (normalise) {
00767       result1 /= p1.getTotalWeight();
00768       result2 /= p2.getTotalWeight();
00769     }
00770   }
00771 }
00772 
00773 #endif
00774 

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