59 bool const with_pendant_length
68 Fulcrum() : mass(0.0), torque(0.0) {}
79 std::unordered_map<PlacementTreeLink const*, Fulcrum> balance;
93 if( it.is_last_iteration() ) {
103 while( link != &it.link() ) {
106 assert(balance.count(link));
109 curr_fulcrum.mass += balance[link].mass;
110 curr_fulcrum.torque += balance[link].mass * edge_data.branch_length;
111 curr_fulcrum.torque += balance[link].torque;
112 link = &link->
next();
117 double place_dist = place->proximal_length;
118 if (with_pendant_length) {
119 place_dist += place->pendant_length;
121 curr_fulcrum.mass += place->like_weight_ratio;
122 curr_fulcrum.torque += place->like_weight_ratio * place_dist;
125 assert( balance.count( &it.link().outer() ) == 0 );
126 balance[ &it.link().outer() ] = curr_fulcrum;
154 size_t num_iterations = 0;
156 size_t max_iterations = 1 +
static_cast<size_t>(
157 *std::max_element(depth_vector.begin(), depth_vector.end())
164 LOG_DBG <<
"max it " << max_iterations;
168 assert (num_iterations <= max_iterations);
171 LOG_DBG <<
"iteration " << num_iterations;
179 double max_torque = -1.0;
184 assert(balance.count( &it_l.link() ) > 0);
187 <<
" with mass " << balance[ &it_l.link() ].mass
188 <<
" and torque " << balance[ &it_l.link() ].torque;
189 if (balance[ &it_l.link() ].torque > max_torque) {
190 max_link = &it_l.link();
191 max_torque = balance[ &it_l.link() ].torque;
193 sum.mass += balance[ &it_l.link() ].mass;
194 sum.torque += balance[ &it_l.link() ].torque;
202 if( &max_link->outer() == prev_link ) {
210 prev_link = max_link;
211 curr_link = &max_link->
outer();
213 LOG_DBG1 <<
"mass sum " <<
sum.mass <<
", torque sum " <<
sum.torque;
223 sum.mass -= balance[max_link].mass;
224 sum.torque -= balance[max_link].torque;
225 sum.torque +=
sum.mass * max_edge_data.branch_length;
228 for(
PqueryPlacement const* place : place_map[ max_link->edge().index() ]) {
229 double p_dist = max_edge_data.branch_length - place->proximal_length;
230 if (with_pendant_length) {
231 p_dist += place->pendant_length;
233 sum.mass += place->like_weight_ratio;
234 sum.torque += place->like_weight_ratio * p_dist;
238 balance[curr_link] =
sum;
239 LOG_DBG1 <<
"stored mass " <<
sum.mass <<
" and torque " <<
sum.torque <<
" at "
242 LOG_DBG <<
"end of iteration " << num_iterations <<
"\n";
247 assert( &curr_link->
edge() == &prev_link->
edge() );
258 <<
" with mass " << balance[curr_link].mass <<
" and torque " << balance[curr_link].torque;
260 <<
" with mass " << balance[prev_link].mass <<
" and torque " << balance[prev_link].torque;
277 Fulcrum prox_fulcrum;
278 Fulcrum dist_fulcrum;
280 assert(balance.count(curr_link) > 0);
281 assert(balance.count(prev_link) > 0);
284 link = &prev_link->
next();
285 while (link != prev_link) {
286 assert(balance.count(link));
287 prox_fulcrum.mass += balance[link].mass;
288 prox_fulcrum.torque += balance[link].torque;
289 link = &link->
next();
292 link = &curr_link->
next();
293 while (link != curr_link) {
294 assert(balance.count(link));
295 dist_fulcrum.mass += balance[link].mass;
296 dist_fulcrum.torque += balance[link].torque;
297 link = &link->
next();
300 LOG_DBG <<
"prox_mass " << prox_fulcrum.mass <<
", prox_torque " << prox_fulcrum.torque;
301 LOG_DBG <<
"dist_mass " << dist_fulcrum.mass <<
", dist_torque " << dist_fulcrum.torque;
315 double approx_proximal_length;
317 if (prox_fulcrum.mass == 0.0 || dist_fulcrum.mass == 0.0) {
318 approx_proximal_length = central_edge_data.
branch_length / 2.0;
320 approx_proximal_length = (dist_fulcrum.torque - prox_fulcrum.torque
321 + (dist_fulcrum.mass * central_edge_data.branch_length))
322 / (dist_fulcrum.mass + prox_fulcrum.mass);
325 LOG_DBG <<
"approx_proximal_length " << approx_proximal_length;
334 Fulcrum prox_sum = prox_fulcrum;
335 Fulcrum dist_sum = balance[prev_link];
337 LOG_DBG <<
"prox_sum mass " << prox_sum.mass <<
", prox_sum torque " << prox_sum.torque;
338 LOG_DBG <<
"dist_sum mass " << dist_sum.mass <<
", dist_sum torque " << dist_sum.torque;
348 LOG_DBG1 <<
"assert " << dist_sum.torque <<
">=" << prox_sum.torque;
362 BalancePoint() : proximal_length(0.0), mass(0.0), pendant_torque(0.0) {}
363 BalancePoint(
double prox_len) : proximal_length(prox_len), mass(0.0), pendant_torque(0.0) {}
365 double proximal_length;
367 double pendant_torque;
375 std::vector<BalancePoint> edge_balance;
376 edge_balance.reserve( place_map[ central_edge->index() ].size() + 2);
377 edge_balance.push_back(BalancePoint(0.0));
387 place_map[ central_edge->index() ].begin(),
388 place_map[ central_edge->index() ].end(),
393 for(
PqueryPlacement const* place : place_map[ central_edge->index() ]) {
394 double place_prox = place->proximal_length;
398 if (place_prox > central_edge_data.branch_length) {
399 LOG_WARN <<
"Placement found that has proximal_length > branch_length.";
400 place_prox = central_edge_data.branch_length;
402 if (place_prox < 0.0) {
403 LOG_WARN <<
"Placement found that has proximal_length < 0.0.";
407 double place_pendant_torque = 0.0;
408 if (with_pendant_length) {
409 place_pendant_torque = place->like_weight_ratio * place->pendant_length;
412 tqs += place_prox * place->like_weight_ratio;
413 mss += place->like_weight_ratio;
415 BalancePoint place_balance;
416 place_balance.proximal_length = place_prox;
417 place_balance.mass = place->like_weight_ratio;
418 place_balance.pendant_torque = place_pendant_torque;
420 edge_balance.push_back(place_balance);
423 tqs += dist_fulcrum.torque - prox_fulcrum.torque
424 + (dist_fulcrum.mass * central_edge_data.branch_length);
425 mss += dist_fulcrum.mass + prox_fulcrum.mass;
426 double solution_without_pendant_length = tqs / mss;
427 LOG_DBG <<
"tqs " << tqs <<
", mss " << mss;
428 LOG_DBG <<
"solution_without_pendant_length " << solution_without_pendant_length;
430 return std::make_pair(central_edge, solution_without_pendant_length);
540 bool const with_pendant_length
546 auto const central_edge = cog.first;
548 double const proximal_length = cog.second;
552 LOG_DBG <<
"prox " << proximal_length;
555 smp.
tree(), ¢ral_edge->primary_node()
558 smp.
tree(), ¢ral_edge->secondary_node()
561 for (
const auto& pqry : smp.
pqueries()) {
562 for(
auto const& place : pqry.placements() ) {
566 if (place.edge().index() == central_edge->index()) {
567 distance = std::abs(place.proximal_length - proximal_length);
573 + node_dist_prox[ place.edge().primary_node().index() ]
574 + place.proximal_length;
578 + node_dist_prox[ place.edge().secondary_node().index() ]
579 + place_edge_data.branch_length - place.proximal_length;
582 dp = central_edge_data.branch_length - proximal_length
583 + node_dist_dist[ place.edge().primary_node().index() ]
584 + place.proximal_length;
587 distance = std::min(pp, std::min(pd, dp));
590 if (with_pendant_length) {
591 distance += place.pendant_length;
593 variance += distance * distance * place.like_weight_ratio;
594 mass += place.like_weight_ratio;
608 bool const with_pendant_length
611 throw std::invalid_argument(
"__FUNCTION__: Incompatible trees.");
620 auto edge_a = cog_a.first;
621 auto edge_b = cog_b.first;
623 double prox_a = cog_a.second;
624 double prox_b = cog_b.second;
628 LOG_INFO <<
"map a COG proximal_length < 0: " << prox_a;
631 LOG_DBG <<
"cog a edge " << edge_a->index() <<
" prox " << prox_a;
632 LOG_DBG <<
"cog b edge " << edge_b->index() <<
" prox " << prox_b;
639 if (edge_a->index() == edge_b->index()) {
641 dist = std::abs(prox_a - prox_b);
646 smp_a.
tree(), &edge_a->primary_node()
649 smp_a.
tree(), &edge_a->secondary_node()
656 + node_dist_a_prox[edge_b->primary_node().index()]
661 + node_dist_a_prox[edge_b->secondary_node().index()]
666 + node_dist_a_dist[edge_b->primary_node().index()]
670 dist = std::min(pp, std::min(pd, dp));