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
|
#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() {}
|
||||||
|
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
|
#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);
|
||||||
|
Reference in New Issue
Block a user