Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "components/zucchini/targets_affinity.h" |
| 6 | |
| 7 | #include <algorithm> |
| 8 | |
Hans Wennborg | 5a340be | 2020-04-28 11:06:24 +0000 | [diff] [blame] | 9 | #include "base/check_op.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 10 | #include "components/zucchini/equivalence_map.h" |
| 11 | |
| 12 | namespace zucchini { |
| 13 | |
| 14 | namespace { |
| 15 | |
| 16 | constexpr uint32_t kNoLabel = 0; |
| 17 | } |
| 18 | |
| 19 | TargetsAffinity::TargetsAffinity() = default; |
| 20 | TargetsAffinity::~TargetsAffinity() = default; |
| 21 | |
| 22 | void TargetsAffinity::InferFromSimilarities( |
| 23 | const EquivalenceMap& equivalences, |
Etienne Pierre-doray | aff4086 | 2021-09-14 17:31:51 +0000 | [diff] [blame] | 24 | const std::deque<offset_t>& old_targets, |
| 25 | const std::deque<offset_t>& new_targets) { |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 26 | forward_association_.assign(old_targets.size(), {}); |
| 27 | backward_association_.assign(new_targets.size(), {}); |
| 28 | |
| 29 | if (old_targets.empty() || new_targets.empty()) |
| 30 | return; |
| 31 | |
| 32 | key_t new_key = 0; |
| 33 | for (auto candidate : equivalences) { // Sorted by |dst_offset|. |
| 34 | DCHECK_GT(candidate.similarity, 0.0); |
| 35 | while (new_key < new_targets.size() && |
| 36 | new_targets[new_key] < candidate.eq.dst_offset) { |
| 37 | ++new_key; |
| 38 | } |
| 39 | |
| 40 | // Visit each new target covered by |candidate.eq| and find / update its |
| 41 | // associated old target. |
| 42 | for (; new_key < new_targets.size() && |
| 43 | new_targets[new_key] < candidate.eq.dst_end(); |
| 44 | ++new_key) { |
| 45 | if (backward_association_[new_key].affinity >= candidate.similarity) |
| 46 | continue; |
| 47 | |
| 48 | DCHECK_GE(new_targets[new_key], candidate.eq.dst_offset); |
| 49 | offset_t old_target = new_targets[new_key] - candidate.eq.dst_offset + |
| 50 | candidate.eq.src_offset; |
| 51 | auto old_it = |
| 52 | std::lower_bound(old_targets.begin(), old_targets.end(), old_target); |
| 53 | // If new target can be mapped via |candidate.eq| to an old target, then |
| 54 | // attempt to associate them. Multiple new targets can compete for the |
| 55 | // same old target. The heuristic here makes selections to maximize |
| 56 | // |candidate.similarity|, and if a tie occurs, minimize new target offset |
| 57 | // (by first-come, first-served). |
| 58 | if (old_it != old_targets.end() && *old_it == old_target) { |
| 59 | key_t old_key = static_cast<key_t>(old_it - old_targets.begin()); |
| 60 | if (candidate.similarity > forward_association_[old_key].affinity) { |
| 61 | // Reset other associations. |
| 62 | if (forward_association_[old_key].affinity > 0.0) |
| 63 | backward_association_[forward_association_[old_key].other] = {}; |
| 64 | if (backward_association_[new_key].affinity > 0.0) |
| 65 | forward_association_[backward_association_[new_key].other] = {}; |
| 66 | // Assign new association. |
| 67 | forward_association_[old_key] = {new_key, candidate.similarity}; |
| 68 | backward_association_[new_key] = {old_key, candidate.similarity}; |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | uint32_t TargetsAffinity::AssignLabels(double min_affinity, |
| 76 | std::vector<uint32_t>* old_labels, |
| 77 | std::vector<uint32_t>* new_labels) { |
| 78 | old_labels->assign(forward_association_.size(), kNoLabel); |
| 79 | new_labels->assign(backward_association_.size(), kNoLabel); |
| 80 | |
| 81 | uint32_t label = kNoLabel + 1; |
| 82 | for (key_t old_key = 0; old_key < forward_association_.size(); ++old_key) { |
| 83 | Association association = forward_association_[old_key]; |
| 84 | if (association.affinity >= min_affinity) { |
| 85 | (*old_labels)[old_key] = label; |
| 86 | DCHECK_EQ(0U, (*new_labels)[association.other]); |
| 87 | (*new_labels)[association.other] = label; |
| 88 | ++label; |
| 89 | } |
| 90 | } |
| 91 | return label; |
| 92 | } |
| 93 | |
| 94 | double TargetsAffinity::AffinityBetween(key_t old_key, key_t new_key) const { |
| 95 | DCHECK_LT(old_key, forward_association_.size()); |
| 96 | DCHECK_LT(new_key, backward_association_.size()); |
| 97 | if (forward_association_[old_key].affinity > 0.0 && |
| 98 | forward_association_[old_key].other == new_key) { |
| 99 | DCHECK_EQ(backward_association_[new_key].other, old_key); |
| 100 | DCHECK_EQ(forward_association_[old_key].affinity, |
| 101 | backward_association_[new_key].affinity); |
| 102 | return forward_association_[old_key].affinity; |
| 103 | } |
| 104 | return -std::max(forward_association_[old_key].affinity, |
| 105 | backward_association_[new_key].affinity); |
| 106 | } |
| 107 | |
| 108 | } // namespace zucchini |