// Copyright (C) 2010 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #undef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_ #ifdef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_ #include #include "../string.h" #include "sample_pair_abstract.h" #include "ordered_sample_pair_abstract.h" namespace dlib { // ---------------------------------------------------------------------------------------- template < typename vector_type, typename distance_function_type, typename alloc, typename T > void find_percent_shortest_edges_randomly ( const vector_type& samples, const distance_function_type& dist_funct, const double percent, const unsigned long num, const T& random_seed, std::vector& out ); /*! requires - 0 < percent <= 1 - num > 0 - random_seed must be convertible to a string by dlib::cast_to_string() - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates to a floating point number ensures - This function randomly samples the space of pairs of integers between 0 and samples.size()-1 inclusive. For each of these pairs, (i,j), a sample_pair is created as follows: sample_pair(i, j, dist_funct(samples[i], samples[j])) num such sample_pair objects are generated, duplicates and pairs with distance values == infinity are removed, and then the top percent of them with the smallest distance are stored into out. - #out.size() <= num*percent - contains_duplicate_pairs(#out) == false - for all valid i: - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()]) - #out[i].distance() < std::numeric_limits::infinity() - random_seed is used to seed the random number generator used by this function. !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type, typename distance_function_type, typename alloc, typename T > void find_approximate_k_nearest_neighbors ( const vector_type& samples, const distance_function_type& dist_funct, const unsigned long k, const unsigned long num, const T& random_seed, std::vector& out ); /*! requires - k > 0 - num > 0 - random_seed must be convertible to a string by dlib::cast_to_string() - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates to a floating point number ensures - This function computes an approximate form of k nearest neighbors. As num grows larger the output of this function converges to the output of the find_k_nearest_neighbors() function defined below. - Specifically, this function randomly samples the space of pairs of integers between 0 and samples.size()-1 inclusive. For each of these pairs, (i,j), a sample_pair is created as follows: sample_pair(i, j, dist_funct(samples[i], samples[j])) num such sample_pair objects are generated and then exact k-nearest-neighbors is performed amongst these sample_pairs and the results are stored into #out. Note that samples with an infinite distance between them are considered to be not connected at all. - contains_duplicate_pairs(#out) == false - for all valid i: - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()]) - #out[i].distance() < std::numeric_limits::infinity() - random_seed is used to seed the random number generator used by this function. !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type, typename distance_function_type, typename alloc > void find_k_nearest_neighbors ( const vector_type& samples, const distance_function_type& dist_funct, const unsigned long k, std::vector& out ); /*! requires - k > 0 - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates to a floating point number ensures - #out == a set of sample_pair objects that represent all the k nearest neighbors in samples according to the given distance function dist_funct. Note that samples with an infinite distance between them are considered to be not connected at all. - for all valid i: - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()]) - #out[i].distance() < std::numeric_limits::infinity() - contains_duplicate_pairs(#out) == false !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > bool contains_duplicate_pairs ( const vector_type& pairs ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - if (pairs contains any elements that are equal according to operator==) then - returns true - else - returns false !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > unsigned long max_index_plus_one ( const vector_type& pairs ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - if (pairs.size() == 0) then - returns 0 - else - returns a number N such that: - for all i: pairs[i].index1() < N && pairs[i].index2() < N - for some j: pairs[j].index1()+1 == N || pairs[j].index2()+1 == N !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > void remove_long_edges ( vector_type& pairs, double distance_threshold ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - Removes all elements of pairs that have a distance value greater than the given threshold. - #pairs.size() <= pairs.size() !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > void remove_short_edges ( vector_type& pairs, double distance_threshold ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - Removes all elements of pairs that have a distance value less than the given threshold. - #pairs.size() <= pairs.size() !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > void remove_percent_longest_edges ( vector_type& pairs, double percent ); /*! requires - 0 <= percent < 1 - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - Removes the given upper percentage of the longest edges in pairs. I.e. this function removes the long edges from pairs. - #pairs.size() == (1-percent)*pairs.size() !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > void remove_percent_shortest_edges ( vector_type& pairs, double percent ); /*! requires - 0 <= percent < 1 - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - Removes the given upper percentage of the shortest edges in pairs. I.e. this function removes the short edges from pairs. - #pairs.size() == (1-percent)*pairs.size() !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > void remove_duplicate_edges ( vector_type& pairs ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - Removes any duplicate edges from pairs. That is, for all elements of pairs, A and B, such that A == B, only one of A or B will be in pairs after this function terminates. - #pairs.size() <= pairs.size() - is_ordered_by_index(#pairs) == true - contains_duplicate_pairs(#pairs) == false !*/ // ---------------------------------------------------------------------------------------- template < typename vector_type > bool is_ordered_by_index ( const vector_type& edges ); /*! requires - vector_type == a type with an interface compatible with std::vector and it must in turn contain objects with an interface compatible with dlib::sample_pair or dlib::ordered_sample_pair. ensures - returns true if and only if the contents of edges are in sorted order according to order_by_index(). That is, we return true if calling std::stable_sort(edges.begin(), edges.end(), &order_by_index) would not change the ordering of elements of edges. !*/ // ---------------------------------------------------------------------------------------- template < typename alloc1, typename alloc2 > void find_neighbor_ranges ( const std::vector& edges, std::vector,alloc2>& neighbors ); /*! requires - is_ordered_by_index(edges) == true (i.e. edges is sorted so that all the edges for a particular node are grouped together) ensures - This function takes a graph, represented by its list of edges, and finds the ranges that contain the edges for each node in the graph. In particular, #neighbors[i] will tell you which edges correspond to the ith node in the graph. - #neighbors.size() == max_index_plus_one(edges) (i.e. neighbors will have an entry for each node in the graph defined by the list of edges) - for all valid i: - all elements of edges such that their index1() value == i are in the range [neighbors[i].first, neighbors[i].second). That is, for all k such that neighbors[i].first <= k < neighbors[i].second: - edges[k].index1() == i. - all edges outside this range have an index1() value != i !*/ // ---------------------------------------------------------------------------------------- template < typename alloc1, typename alloc2 > void convert_unordered_to_ordered ( const std::vector& edges, std::vector& out_edges ); /*! ensures - interprets edges a defining an undirected graph. - This function populates out_edges with a directed graph that represents the same graph as the one in edges. In particular, this means that for all valid i we have the following: - if (edges[i].index1() != edges[i].index2()) then - #out_edges contains two edges corresponding to edges[i]. They represent the two directions of this edge. The distance value from edges[i] is also copied into the output edges. - else - #out_edges contains one edge corresponding to edges[i] since this is a self edge. The distance value from edges[i] is also copied into the output edge. - max_index_plus_one(edges) == max_index_plus_one(#out_edges) (i.e. both graphs have the same number of nodes) - In all but the most trivial cases, we will have is_ordered_by_index(#out_edges) == false - contains_duplicate_pairs(#out_edges) == contains_duplicate_pairs(edges) !*/ // ---------------------------------------------------------------------------------------- } #endif // DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_