Skip to content

Commit d9870a9

Browse files
[LibVTR][Math] Handled Pre-sorting Median Calculation
1 parent 560e793 commit d9870a9

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "alloc_and_load_rr_indexed_data.h"
22

3+
#include <algorithm>
34
#include <cmath> /* Needed only for sqrt call (remove if sqrt removed) */
45
#include <fstream>
56
#include <iomanip>
@@ -592,8 +593,10 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph,
592593
auto switch_Cinternal_total_histogram = build_histogram(switch_Cinternal_total[RRIndexedDataId(cost_index)], 10);
593594

594595
// Sort Rnode and Cnode
595-
float Cnode = vtr::median<float>(C_total[RRIndexedDataId(cost_index)]);
596-
float Rnode = vtr::median<float>(R_total[RRIndexedDataId(cost_index)]);
596+
std::sort(C_total[RRIndexedDataId(cost_index)].begin(), C_total[RRIndexedDataId(cost_index)].end());
597+
std::sort(R_total[RRIndexedDataId(cost_index)].begin(), R_total[RRIndexedDataId(cost_index)].end());
598+
float Cnode = vtr::median_presorted<float>(C_total[RRIndexedDataId(cost_index)]);
599+
float Rnode = vtr::median_presorted<float>(R_total[RRIndexedDataId(cost_index)]);
597600
float Rsw = get_histogram_mode(switch_R_total_histogram);
598601
float Tsw = get_histogram_mode(switch_T_total_histogram);
599602
float Cinternalsw = get_histogram_mode(switch_Cinternal_total_histogram);

libs/libvtrutil/src/vtr_math.h

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <algorithm>
34
#include <iterator>
45
#include <map>
56
#include <vector>
@@ -36,8 +37,10 @@ T safe_ratio(T numerator, T denominator) {
3637
///@brief Returns the median of the elements in range [first, last)
3738
/// If there are an odd number of elements in the range, returns the
3839
/// average of the two middle elements (equal distance from the start and end).
40+
/// NOTE: This method assumes that the container that first and last point to are
41+
/// pre-sorted
3942
template<typename ResultTy = double, typename InputIterator>
40-
ResultTy median(InputIterator first, InputIterator last) {
43+
ResultTy median_presorted(const InputIterator first, const InputIterator last) {
4144
// If the distance between first and last is 0 (meaning the set is empty),
4245
// return a quiet NaN. This should be handled by the user of this code.
4346
// NOTE: This returns a NaN of double type.
@@ -66,10 +69,22 @@ ResultTy median(InputIterator first, InputIterator last) {
6669
}
6770
}
6871

69-
///@brief Returns the median of a whole container
72+
///@brief Returns the median of a whole container, assuming the container has
73+
/// not been pre-sorted.
74+
/// Note: This function is pass by value since the container needs to be
75+
/// sorted. If the container is already sorted, use median_presorted to
76+
/// avoid the copy.
7077
template<typename ResultTy = double, typename Container>
7178
ResultTy median(Container c) {
72-
return median<ResultTy>(std::begin(c), std::end(c));
79+
std::sort(std::begin(c), std::end(c));
80+
return median_presorted<ResultTy>(std::begin(c), std::end(c));
81+
}
82+
83+
///@brief Returns the median of a whole container, assuming that it is already
84+
/// sorted.
85+
template<typename ResultTy = double, typename Container>
86+
ResultTy median_presorted(const Container &c) {
87+
return median_presorted<ResultTy>(std::begin(c), std::end(c));
7388
}
7489

7590
/**
@@ -84,7 +99,7 @@ ResultTy median(Container c) {
8499
* geomean = exp( (1 / n) * (log(v_1) + log(v_2) + ... + log(v_n)))
85100
*/
86101
template<typename InputIterator>
87-
double geomean(InputIterator first, InputIterator last, double init = 1.) {
102+
double geomean(const InputIterator first, const InputIterator last, double init = 1.) {
88103
double log_sum = std::log(init);
89104
size_t n = 0;
90105
for (auto iter = first; iter != last; ++iter) {
@@ -101,13 +116,13 @@ double geomean(InputIterator first, InputIterator last, double init = 1.) {
101116

102117
///@brief Returns the geometric mean of a whole container
103118
template<typename Container>
104-
double geomean(Container c) {
119+
double geomean(const Container &c) {
105120
return geomean(std::begin(c), std::end(c));
106121
}
107122

108123
///@brief Returns the arithmatic mean of the elements in range [first, last)
109124
template<typename InputIterator>
110-
double arithmean(InputIterator first, InputIterator last, double init = 0.) {
125+
double arithmean(const InputIterator first, const InputIterator last, double init = 0.) {
111126
double sum = init;
112127
size_t n = 0;
113128
for (auto iter = first; iter != last; ++iter) {
@@ -124,7 +139,7 @@ double arithmean(InputIterator first, InputIterator last, double init = 0.) {
124139

125140
///@brief Returns the aritmatic mean of a whole container
126141
template<typename Container>
127-
double arithmean(Container c) {
142+
double arithmean(const Container &c) {
128143
return arithmean(std::begin(c), std::end(c));
129144
}
130145

libs/libvtrutil/test/test_math.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <cmath>
22
#include <limits>
3+
#include <vector>
34

45
#include "catch2/catch_test_macros.hpp"
56
#include "catch2/catch_approx.hpp"
@@ -62,46 +63,62 @@ TEST_CASE("Median", "[vtr_math]") {
6263
// Check the median of a vector with a singular value.
6364
std::vector<double> single_vec = {1.0};
6465
REQUIRE(vtr::median(single_vec) == 1.0);
66+
REQUIRE(vtr::median_presorted(single_vec) == 1.0);
6567

6668
// Check the median of a vector with two elements.
6769
std::vector<double> double_vec = {1.0, 2.0};
6870
REQUIRE(vtr::median(double_vec) == 1.5);
71+
REQUIRE(vtr::median_presorted(double_vec) == 1.5);
6972

7073
// Check the median of a vector with an odd length.
7174
std::vector<double> odd_vec = {1.0, 2.0, 3.0, 4.0, 5.0};
7275
REQUIRE(vtr::median(odd_vec) == 3.0);
76+
REQUIRE(vtr::median_presorted(odd_vec) == 3.0);
7377

7478
// Check the median of a vector with a median length.
7579
std::vector<double> even_vec = {1.0, 2.0, 3.0, 4.0};
7680
REQUIRE(vtr::median(even_vec) == 2.5);
7781

82+
// Check unsorted list gives correct median.
83+
std::vector<double> unsorted_odd_vec = {2.0, 3.0, 1.0, 5.0, 4.0};
84+
REQUIRE(vtr::median(unsorted_odd_vec) == 3.0);
85+
std::vector<double> unsorted_even_vec = {2.0, 3.0, 1.0, 4.0};
86+
REQUIRE(vtr::median(unsorted_even_vec) == 2.5);
87+
7888
// Check the median of a negative, odd-lengthed vector works.
7989
std::vector<double> negative_odd_vec = {-1.0, -2.0, -3.0, -4.0, -5.0};
8090
REQUIRE(vtr::median(negative_odd_vec) == -3.0);
91+
REQUIRE(vtr::median_presorted(negative_odd_vec) == -3.0);
8192

8293
// Check the median of a negative, even-lengthed vector works.
8394
std::vector<double> negative_even_vec = {-1.0, -2.0, -3.0, -4.0};
8495
REQUIRE(vtr::median(negative_even_vec) == -2.5);
96+
REQUIRE(vtr::median_presorted(negative_even_vec) == -2.5);
8597

8698
// Check the median of an fp vector with an odd length.
8799
std::vector<float> fp_odd_vec = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
88100
REQUIRE(vtr::median(fp_odd_vec) == 3.0);
89101
REQUIRE(vtr::median<float>(fp_odd_vec) == 3.0f);
102+
REQUIRE(vtr::median_presorted<float>(fp_odd_vec) == 3.0f);
90103

91104
// Check the median of an fp vector with a median length.
92105
std::vector<float> fp_even_vec = {1.0f, 2.0f, 3.0f, 4.0f};
93106
REQUIRE(vtr::median(fp_even_vec) == 2.5);
94107
REQUIRE(vtr::median<float>(fp_even_vec) == 2.5f);
108+
REQUIRE(vtr::median_presorted<float>(fp_even_vec) == 2.5f);
95109

96110
// Check the median of an integral, odd-lengthed vecor.
97111
std::vector<int> int_vec_odd = {1, 2, 3, 4, 5};
98112
REQUIRE(vtr::median(int_vec_odd) == 3.0);
113+
REQUIRE(vtr::median_presorted(int_vec_odd) == 3.0);
99114

100115
// Check the median of an integral, even-lengthed vecor.
101116
std::vector<int> int_vec_even = {1, 2, 3, 4};
102117
REQUIRE(vtr::median(int_vec_even) == 2.5);
118+
REQUIRE(vtr::median_presorted(int_vec_even) == 2.5);
103119

104120
// Check that trying to get the median of an empty vector returns a NaN.
105121
std::vector<double> empty_vec;
106122
REQUIRE(std::isnan(vtr::median(empty_vec)));
123+
REQUIRE(std::isnan(vtr::median_presorted(empty_vec)));
107124
}

vpr/src/place/delay_model/compute_delta_delays_utils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,8 @@ static float delay_reduce(std::vector<float>& delays, e_reducer reducer) {
705705
auto itr = std::max_element(delays.begin(), delays.end());
706706
delay = *itr;
707707
} else if (reducer == e_reducer::MEDIAN) {
708-
std::stable_sort(delays.begin(), delays.end());
709-
delay = vtr::median<float>(delays.begin(), delays.end());
708+
std::sort(delays.begin(), delays.end());
709+
delay = vtr::median_presorted<float>(delays.begin(), delays.end());
710710
} else if (reducer == e_reducer::ARITHMEAN) {
711711
delay = vtr::arithmean(delays.begin(), delays.end());
712712
} else if (reducer == e_reducer::GEOMEAN) {

0 commit comments

Comments
 (0)