forked from boostorg/algorithm
Added some concept checking, and renamed a few template parameters.
[SVN r45227]
This commit is contained in:
@ -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
|
||||
#define BOOST_ALGORITHM_CLUSTER_CLUSTER_DATA_HPP
|
||||
|
||||
@ -13,10 +18,10 @@ namespace cluster
|
||||
|
||||
/*! TODO: Document this type.
|
||||
*/
|
||||
template<typename Cluster>
|
||||
template<typename ClusterT>
|
||||
struct cluster_data
|
||||
{
|
||||
typedef Cluster value_type;
|
||||
typedef ClusterT value_type;
|
||||
typedef std::vector<value_type> clusters;
|
||||
cluster_data() : m_pClusters(new clusters) {}
|
||||
~cluster_data() {}
|
||||
|
38
include/boost/algorithm/cluster/concept.hpp
Normal file
38
include/boost/algorithm/cluster/concept.hpp
Normal 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
|
@ -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
|
||||
#define BOOST_ALGORITHM_CLUSTER_DBSCAN_HPP
|
||||
|
||||
#include <boost/algorithm/cluster/cluster_data.hpp>
|
||||
#include <boost/algorithm/cluster/concept.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
@ -13,19 +19,22 @@ namespace cluster
|
||||
|
||||
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.
|
||||
// This query mechanism makes the runtime quadratic.
|
||||
template<typename NTupleIter, typename DistFun>
|
||||
template<typename NTupleIterT, typename DistFunT>
|
||||
static void query(
|
||||
NTupleIter const & query_pt,
|
||||
NTupleIter const & begin,
|
||||
NTupleIter const & end,
|
||||
typename NTupleIter::difference_type eps,
|
||||
DistFun const & d,
|
||||
std::vector<NTupleIter> & v)
|
||||
NTupleIterT const & query_pt,
|
||||
NTupleIterT const & begin,
|
||||
NTupleIterT const & end,
|
||||
typename NTupleIterT::difference_type eps,
|
||||
DistFunT const & d,
|
||||
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)
|
||||
continue;
|
||||
@ -38,12 +47,12 @@ static void query(
|
||||
}
|
||||
|
||||
// TODO: Replace this so we don't have to store the cluster info for each tuple?
|
||||
template<typename NTupleIter>
|
||||
template<typename NTupleIterT>
|
||||
struct node
|
||||
{
|
||||
node(NTupleIter const & t) : tuple(t), cluster(UNCLASSIFIED) {}
|
||||
node(NTupleIterT const & t) : tuple(t), cluster(UNCLASSIFIED) {}
|
||||
|
||||
NTupleIter tuple;
|
||||
NTupleIterT tuple;
|
||||
int cluster;
|
||||
};
|
||||
|
||||
@ -58,31 +67,33 @@ struct node
|
||||
* \param[in] d
|
||||
* \return The cluster data (partitioning of the tuples).
|
||||
*/
|
||||
template<typename Cluster, typename NTupleIter, typename DistFun>
|
||||
cluster_data<Cluster>
|
||||
dbscan(NTupleIter const & begin,
|
||||
NTupleIter const & end,
|
||||
typename NTupleIter::difference_type const & eps,
|
||||
template<typename ClusterT, typename NTupleIterT, typename DistFunT>
|
||||
cluster_data<ClusterT>
|
||||
dbscan(NTupleIterT const & begin,
|
||||
NTupleIterT const & end,
|
||||
typename NTupleIterT::difference_type const & eps,
|
||||
size_t min_points,
|
||||
DistFun const & d)
|
||||
DistFunT const & d)
|
||||
{
|
||||
int const UNCLASSIFIED = -1;
|
||||
int const NOISE = 0;
|
||||
// Concept check.
|
||||
function_requires<
|
||||
DistanceComparableConcept<typename NTupleIterT::value_type, DistFunT> >();
|
||||
//DistanceComparableConcept<int, DistFunT> >();
|
||||
|
||||
// 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;
|
||||
ntuple_nodes tuples;
|
||||
|
||||
// Initialize algorithm.
|
||||
//size_t num_elems = 0;
|
||||
for(NTupleIter it = begin; it != end; ++it)
|
||||
for(NTupleIterT it = begin; it != end; ++it)
|
||||
{
|
||||
//++num_elems;
|
||||
tuples.push_back(node(it));
|
||||
}
|
||||
|
||||
typedef cluster_data<std::vector<NTupleIter> > cluster_data;
|
||||
typedef cluster_data<std::vector<NTupleIterT> > cluster_data;
|
||||
cluster_data p;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Skip this tuple if its already been classified as a cluster or noise.
|
||||
if (it->cluster != UNCLASSIFIED)
|
||||
if (it->cluster != detail::UNCLASSIFIED)
|
||||
continue;
|
||||
|
||||
// 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 (seeds.size() < min_points)
|
||||
{
|
||||
it->cluster = NOISE;
|
||||
it->cluster = detail::NOISE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start the next cluster.
|
||||
++cluster_num;
|
||||
p.push_back(Cluster()); // TODO: This is goofy.
|
||||
Cluster & cur_cluster = p.back();
|
||||
p.push_back(ClusterT()); // TODO: This is goofy.
|
||||
ClusterT & cur_cluster = p.back();
|
||||
|
||||
// Mark entire neighborhood as part of the current cluster.
|
||||
it->cluster = cluster_num;
|
||||
@ -134,7 +145,7 @@ dbscan(NTupleIter const & begin,
|
||||
{
|
||||
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]);
|
||||
results[n]->cluster = cluster_num;
|
||||
cur_cluster.push_back(results[n]->tuple);
|
||||
|
Reference in New Issue
Block a user