64 throw std::runtime_error(
65 "Invalid exponent value p for earth mover's distance calculation. Has to be > 0.0."
78 throw std::invalid_argument(
"MassTrees need to have same size." );
89 auto node_masses = std::vector<double>( lhs.
node_count(), 0.0 );
100 for( ; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it ) {
106 if( lhs_it.is_last_iteration() || rhs_it.is_last_iteration() ) {
108 if( ! lhs_it.is_last_iteration() || ! rhs_it.is_last_iteration() ) {
109 throw std::invalid_argument(
"Incompatible MassTrees." );
115 const size_t pri_node_index = lhs_it.edge().primary_node().index();
116 const size_t sec_node_index = lhs_it.edge().secondary_node().index();
120 pri_node_index != rhs_it.edge().primary_node().index() ||
121 sec_node_index != rhs_it.edge().secondary_node().index()
123 throw std::invalid_argument(
"Incompatible MassTrees." );
128 assert( sec_node_index == lhs_it.node().index() );
129 assert( sec_node_index == rhs_it.node().index() );
136 edge_masses[ mass.first ] -= mass.second;
141 double current_pos = std::max(
145 double current_mass = node_masses[ sec_node_index ];
150 auto mass_rit = edge_masses.crbegin();
151 mass_rit != edge_masses.crend();
156 work += std::pow( std::abs( current_mass ), p ) * ( current_pos - mass_rit->first );
159 current_pos = mass_rit->first;
160 current_mass += mass_rit->second;
166 work += std::pow( std::abs( current_mass ), p ) * current_pos;
167 node_masses[ pri_node_index ] += current_mass;
171 if( lhs_it != lhs_end || rhs_it != rhs_end ) {
172 throw std::invalid_argument(
"Incompatible MassTrees." );
177 work = std::pow( work, 1.0 / p );
187 throw std::runtime_error(
188 "Invalid exponent value p for earth mover's distance calculation. Has to be > 0.0."
196 #ifdef GENESIS_OPENMP
204 #pragma omp parallel for schedule( dynamic )
205 for(
size_t k = 0; k < max_k; ++k ) {
209 auto const i = ij.first;
210 auto const j = ij.second;
214 result( i, j ) = emd;
215 result( j, i ) = emd;
221 for(
size_t i = 0; i < trees.size(); ++i ) {
224 for(
size_t j = i + 1; j < trees.size(); ++j ) {
227 result( i, j ) = emd;
228 result( j, i ) = emd;
241 throw std::runtime_error(
242 "Invalid exponent value p for earth mover's distance calculation. Has to be > 0.0."
254 auto node_masses = std::vector<double>( tree.
node_count(), 0.0 );
267 if( tree_it.is_last_iteration() ) {
272 const size_t pri_node_index = tree_it.edge().primary_node().index();
273 const size_t sec_node_index = tree_it.edge().secondary_node().index();
277 assert( sec_node_index == tree_it.node().index() );
282 double current_mass = node_masses[ sec_node_index ];
288 auto mass_rit = edge_masses.crbegin();
289 mass_rit != edge_masses.crend();
294 work += std::pow( std::abs( current_mass ), p ) * ( current_pos - mass_rit->first );
297 current_pos = mass_rit->first;
298 current_mass += mass_rit->second;
305 work += std::pow( std::abs( current_mass ), p ) * current_pos;
306 node_masses[ pri_node_index ] += current_mass;
311 work = std::pow( work, 1.0 / p );