Added some concept checking, and renamed a few template parameters.

[SVN r45227]
This commit is contained in:
Jonathan Franklin
2008-05-08 20:05:46 +00:00
parent c91fe00184
commit cdf58b4785
3 changed files with 83 additions and 29 deletions

View File

@ -1,3 +1,8 @@
// (C) Copyright Jonathan Franklin 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if ! defined BOOST_ALGORITHM_CLUSTER_CLUSTER_DATA_HPP #if ! defined BOOST_ALGORITHM_CLUSTER_CLUSTER_DATA_HPP
#define BOOST_ALGORITHM_CLUSTER_CLUSTER_DATA_HPP #define BOOST_ALGORITHM_CLUSTER_CLUSTER_DATA_HPP
@ -13,10 +18,10 @@ namespace cluster
/*! TODO: Document this type. /*! TODO: Document this type.
*/ */
template<typename Cluster> template<typename ClusterT>
struct cluster_data struct cluster_data
{ {
typedef Cluster value_type; typedef ClusterT value_type;
typedef std::vector<value_type> clusters; typedef std::vector<value_type> clusters;
cluster_data() : m_pClusters(new clusters) {} cluster_data() : m_pClusters(new clusters) {}
~cluster_data() {} ~cluster_data() {}

View File

@ -0,0 +1,38 @@
// (C) Copyright Jonathan Franklin 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if ! defined BOOST_ALGORITHM_CLUSTER_CONCEPT_HPP
#define BOOST_ALGORITHM_CLUSTER_CONCEPT_HPP
#include <boost/concept_check.hpp>
namespace boost
{
namespace algorithm
{
namespace cluster
{
// TODO: Document the purpose of this concept.
template<typename T, typename DistanceFunT>
struct DistanceComparableConcept
{
void constraints()
{
// Operation
d(t, t);
}
private:
T t;
DistanceFunT d;
};
// TODO: Add concepts here, then delete this comment.
} // End of namespace cluster;
} // End of namespace algorithm;
} // End of namespace boost;
#endif // BOOST_ALGORITHM_CLUSTER_CONCEPT_HPP

View File

@ -1,7 +1,13 @@
// (C) Copyright Jonathan Franklin 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if ! defined BOOST_ALGORITHM_CLUSTER_DBSCAN_HPP #if ! defined BOOST_ALGORITHM_CLUSTER_DBSCAN_HPP
#define BOOST_ALGORITHM_CLUSTER_DBSCAN_HPP #define BOOST_ALGORITHM_CLUSTER_DBSCAN_HPP
#include <boost/algorithm/cluster/cluster_data.hpp> #include <boost/algorithm/cluster/cluster_data.hpp>
#include <boost/algorithm/cluster/concept.hpp>
#include <vector> #include <vector>
namespace boost namespace boost
@ -13,19 +19,22 @@ namespace cluster
namespace detail namespace detail
{ {
// TODO: Where should we put these?
int const UNCLASSIFIED = -1;
int const NOISE = 0;
// TODO: Replace this naive query function w/ R*-tree or fractional cascading. // TODO: Replace this naive query function w/ R*-tree or fractional cascading.
// This query mechanism makes the runtime quadratic. // This query mechanism makes the runtime quadratic.
template<typename NTupleIter, typename DistFun> template<typename NTupleIterT, typename DistFunT>
static void query( static void query(
NTupleIter const & query_pt, NTupleIterT const & query_pt,
NTupleIter const & begin, NTupleIterT const & begin,
NTupleIter const & end, NTupleIterT const & end,
typename NTupleIter::difference_type eps, typename NTupleIterT::difference_type eps,
DistFun const & d, DistFunT const & d,
std::vector<NTupleIter> & v) std::vector<NTupleIterT> & v)
{ {
for(NTupleIter cur_pt = begin; cur_pt != end; ++cur_pt) for(NTupleIterT cur_pt = begin; cur_pt != end; ++cur_pt)
{ {
if (query_pt == cur_pt) if (query_pt == cur_pt)
continue; continue;
@ -38,12 +47,12 @@ static void query(
} }
// TODO: Replace this so we don't have to store the cluster info for each tuple? // TODO: Replace this so we don't have to store the cluster info for each tuple?
template<typename NTupleIter> template<typename NTupleIterT>
struct node struct node
{ {
node(NTupleIter const & t) : tuple(t), cluster(UNCLASSIFIED) {} node(NTupleIterT const & t) : tuple(t), cluster(UNCLASSIFIED) {}
NTupleIter tuple; NTupleIterT tuple;
int cluster; int cluster;
}; };
@ -58,31 +67,33 @@ struct node
* \param[in] d * \param[in] d
* \return The cluster data (partitioning of the tuples). * \return The cluster data (partitioning of the tuples).
*/ */
template<typename Cluster, typename NTupleIter, typename DistFun> template<typename ClusterT, typename NTupleIterT, typename DistFunT>
cluster_data<Cluster> cluster_data<ClusterT>
dbscan(NTupleIter const & begin, dbscan(NTupleIterT const & begin,
NTupleIter const & end, NTupleIterT const & end,
typename NTupleIter::difference_type const & eps, typename NTupleIterT::difference_type const & eps,
size_t min_points, size_t min_points,
DistFun const & d) DistFunT const & d)
{ {
int const UNCLASSIFIED = -1; // Concept check.
int const NOISE = 0; function_requires<
DistanceComparableConcept<typename NTupleIterT::value_type, DistFunT> >();
//DistanceComparableConcept<int, DistFunT> >();
// TODO: Rework the algorithm to NOT make this extra collection? // TODO: Rework the algorithm to NOT make this extra collection?
typedef detail::node<NTupleIter> node; typedef detail::node<NTupleIterT> node;
typedef std::vector<node> ntuple_nodes; typedef std::vector<node> ntuple_nodes;
ntuple_nodes tuples; ntuple_nodes tuples;
// Initialize algorithm. // Initialize algorithm.
//size_t num_elems = 0; //size_t num_elems = 0;
for(NTupleIter it = begin; it != end; ++it) for(NTupleIterT it = begin; it != end; ++it)
{ {
//++num_elems; //++num_elems;
tuples.push_back(node(it)); tuples.push_back(node(it));
} }
typedef cluster_data<std::vector<NTupleIter> > cluster_data; typedef cluster_data<std::vector<NTupleIterT> > cluster_data;
cluster_data p; cluster_data p;
// TODO: We should try to make cluster_num go away. // TODO: We should try to make cluster_num go away.
@ -90,7 +101,7 @@ dbscan(NTupleIter const & begin,
for(ntuple_nodes::iterator it = tuples.begin(); it != tuples.end(); ++it) for(ntuple_nodes::iterator it = tuples.begin(); it != tuples.end(); ++it)
{ {
// Skip this tuple if its already been classified as a cluster or noise. // Skip this tuple if its already been classified as a cluster or noise.
if (it->cluster != UNCLASSIFIED) if (it->cluster != detail::UNCLASSIFIED)
continue; continue;
// Expand cluster. // Expand cluster.
@ -100,14 +111,14 @@ dbscan(NTupleIter const & begin,
// If the neighborhood of this tuple is too small, then mark it as noise. // If the neighborhood of this tuple is too small, then mark it as noise.
if (seeds.size() < min_points) if (seeds.size() < min_points)
{ {
it->cluster = NOISE; it->cluster = detail::NOISE;
continue; continue;
} }
// Start the next cluster. // Start the next cluster.
++cluster_num; ++cluster_num;
p.push_back(Cluster()); // TODO: This is goofy. p.push_back(ClusterT()); // TODO: This is goofy.
Cluster & cur_cluster = p.back(); ClusterT & cur_cluster = p.back();
// Mark entire neighborhood as part of the current cluster. // Mark entire neighborhood as part of the current cluster.
it->cluster = cluster_num; it->cluster = cluster_num;
@ -134,7 +145,7 @@ dbscan(NTupleIter const & begin,
{ {
if (results[n]->cluster < 1) // Not assigned to cluster yet. if (results[n]->cluster < 1) // Not assigned to cluster yet.
{ {
if (UNCLASSIFIED == results[n]->cluster) if (detail::UNCLASSIFIED == results[n]->cluster)
seeds.push_back(results[n]); seeds.push_back(results[n]);
results[n]->cluster = cluster_num; results[n]->cluster = cluster_num;
cur_cluster.push_back(results[n]->tuple); cur_cluster.push_back(results[n]->tuple);