• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/decoder/quantization.h"
16 #include "src/decoder/integer_sequence_codec.h"
17 
18 #include <gtest/gtest.h>
19 
20 #include <functional>
21 #include <string>
22 #include <vector>
23 
24 namespace astc_codec {
25 
26 namespace {
27 
28 // Make sure that we never exceed the maximum range that we pass in.
TEST(QuantizationTest,TestQuantizeMaxRange)29 TEST(QuantizationTest, TestQuantizeMaxRange) {
30   for (int i = kEndpointRangeMinValue; i < 256; ++i) {
31     EXPECT_LE(QuantizeCEValueToRange(255, i), i);
32   }
33 
34   for (int i = 1; i < kWeightRangeMaxValue; ++i) {
35     EXPECT_LE(QuantizeWeightToRange(64, i), i);
36   }
37 }
38 
39 // Make sure that whenever we unquantize and requantize a value we get back
40 // what we started with.
TEST(QuantizationTest,TestReversibility)41 TEST(QuantizationTest, TestReversibility) {
42   for (auto itr = ISERangeBegin(); itr != ISERangeEnd(); itr++) {
43     const int range = *itr;
44     if (range <= kWeightRangeMaxValue) {
45       for (int j = 0; j <= range; ++j) {
46         const int q = UnquantizeWeightFromRange(j, range);
47         EXPECT_EQ(QuantizeWeightToRange(q, range), j);
48       }
49     }
50 
51     if (range >= kEndpointRangeMinValue) {
52       for (int j = 0; j <= range; ++j) {
53         const int q = UnquantizeCEValueFromRange(j, range);
54         EXPECT_EQ(QuantizeCEValueToRange(q, range), j);
55       }
56     }
57   }
58 }
59 
60 // Make sure that whenever we quantize a non-maximal value it gets sent to the
61 // proper range
TEST(QuantizationTest,TestQuantizationRange)62 TEST(QuantizationTest, TestQuantizationRange) {
63   for (auto itr = ISERangeBegin(); itr != ISERangeEnd(); itr++) {
64     const int range = *itr;
65     if (range >= kEndpointRangeMinValue) {
66       EXPECT_LE(QuantizeCEValueToRange(0, range), range);
67       EXPECT_LE(QuantizeCEValueToRange(4, range), range);
68       EXPECT_LE(QuantizeCEValueToRange(15, range), range);
69       EXPECT_LE(QuantizeCEValueToRange(22, range), range);
70       EXPECT_LE(QuantizeCEValueToRange(66, range), range);
71       EXPECT_LE(QuantizeCEValueToRange(91, range), range);
72       EXPECT_LE(QuantizeCEValueToRange(126, range), range);
73     }
74 
75     if (range <= kWeightRangeMaxValue) {
76       EXPECT_LE(QuantizeWeightToRange(0, range), range);
77       EXPECT_LE(QuantizeWeightToRange(4, range), range);
78       EXPECT_LE(QuantizeWeightToRange(15, range), range);
79       EXPECT_LE(QuantizeWeightToRange(22, range), range);
80     }
81   }
82 }
83 
84 // Make sure that whenever we unquantize a value it remains within [0, 255]
TEST(QuantizationTest,TestUnquantizationRange)85 TEST(QuantizationTest, TestUnquantizationRange) {
86   EXPECT_LT(UnquantizeCEValueFromRange(2, 7), 256);
87   EXPECT_LT(UnquantizeCEValueFromRange(7, 7), 256);
88   EXPECT_LT(UnquantizeCEValueFromRange(39, 63), 256);
89   EXPECT_LT(UnquantizeCEValueFromRange(66, 79), 256);
90   EXPECT_LT(UnquantizeCEValueFromRange(91, 191), 256);
91   EXPECT_LT(UnquantizeCEValueFromRange(126, 255), 256);
92   EXPECT_LT(UnquantizeCEValueFromRange(255, 255), 256);
93 
94   EXPECT_LE(UnquantizeWeightFromRange(0, 1), 64);
95   EXPECT_LE(UnquantizeWeightFromRange(2, 7), 64);
96   EXPECT_LE(UnquantizeWeightFromRange(7, 7), 64);
97   EXPECT_LE(UnquantizeWeightFromRange(29, 31), 64);
98 }
99 
100 // When we quantize a value, it should use the largest quantization range that
101 // does not exceed the desired range.
TEST(QuantizationTest,TestUpperBoundRanges)102 TEST(QuantizationTest, TestUpperBoundRanges) {
103   auto expected_range_itr = ISERangeBegin();
104   for (int desired_range = 1; desired_range < 256; ++desired_range) {
105     if (desired_range == *(expected_range_itr + 1)) {
106       ++expected_range_itr;
107     }
108     const int expected_range = *expected_range_itr;
109     ASSERT_LE(expected_range, desired_range);
110 
111     if (desired_range >= kEndpointRangeMinValue) {
112       EXPECT_EQ(QuantizeCEValueToRange(0, desired_range),
113                 QuantizeCEValueToRange(0, expected_range));
114 
115       EXPECT_EQ(QuantizeCEValueToRange(208, desired_range),
116                 QuantizeCEValueToRange(208, expected_range));
117 
118       EXPECT_EQ(QuantizeCEValueToRange(173, desired_range),
119                 QuantizeCEValueToRange(173, expected_range));
120 
121       EXPECT_EQ(QuantizeCEValueToRange(13, desired_range),
122                 QuantizeCEValueToRange(13, expected_range));
123 
124       EXPECT_EQ(QuantizeCEValueToRange(255, desired_range),
125                 QuantizeCEValueToRange(255, expected_range));
126     }
127 
128     if (desired_range <= kWeightRangeMaxValue) {
129       EXPECT_EQ(QuantizeWeightToRange(0, desired_range),
130                 QuantizeWeightToRange(0, expected_range));
131 
132       EXPECT_EQ(QuantizeWeightToRange(63, desired_range),
133                 QuantizeWeightToRange(63, expected_range));
134 
135       EXPECT_EQ(QuantizeWeightToRange(12, desired_range),
136                 QuantizeWeightToRange(12, expected_range));
137 
138       EXPECT_EQ(QuantizeWeightToRange(23, desired_range),
139                 QuantizeWeightToRange(23, expected_range));
140     }
141   }
142 
143   // Make sure that we covered all the possible ranges
144   ASSERT_EQ(std::next(expected_range_itr), ISERangeEnd());
145 }
146 
147 // Make sure that quantizing to the largest range is the identity function.
TEST(QuantizationTest,TestIdentity)148 TEST(QuantizationTest, TestIdentity) {
149   for (int i = 0; i < 256; ++i) {
150     EXPECT_EQ(QuantizeCEValueToRange(i, 255), i);
151   }
152 
153   // Note: This doesn't apply to weights since there's a weird hack to convert
154   // values from [0, 31] to [0, 64].
155 }
156 
157 // Make sure that bit quantization is monotonic with respect to the input,
158 // since quantizing and dequantizing bits is a matter of truncation and bit
159 // replication
TEST(QuantizationTest,TestMonotonicBitPacking)160 TEST(QuantizationTest, TestMonotonicBitPacking) {
161   for (int num_bits = 3; num_bits < 8; ++num_bits) {
162     const int range = (1 << num_bits) - 1;
163     int last_quant_val = -1;
164     for (int i = 0; i < 256; ++i) {
165       const int quant_val = QuantizeCEValueToRange(i, range);
166       EXPECT_LE(last_quant_val, quant_val);
167       last_quant_val = quant_val;
168     }
169 
170     // Also expect the last quantization val to be equal to the range
171     EXPECT_EQ(last_quant_val, range);
172 
173     if (range <= kWeightRangeMaxValue) {
174       last_quant_val = -1;
175       for (int i = 0; i <= 64; ++i) {
176         const int quant_val = QuantizeWeightToRange(i, range);
177         EXPECT_LE(last_quant_val, quant_val);
178         last_quant_val = quant_val;
179       }
180       EXPECT_EQ(last_quant_val, range);
181     }
182   }
183 }
184 
185 // Make sure that bit quantization reflects that quantized values below the bit
186 // replication threshold get mapped to zero
TEST(QuantizationTest,TestSmallBitPacking)187 TEST(QuantizationTest, TestSmallBitPacking) {
188   for (int num_bits = 1; num_bits <= 8; ++num_bits) {
189     const int range = (1 << num_bits) - 1;
190 
191     // The largest number that should map to zero is one less than half of the
192     // smallest representation w.r.t. range. For example: if we have a range
193     // of 7, it means that we have 3 total bits abc for quantized values. If we
194     // unquantize to 8 bits, it means that our resulting value will be abcabcab.
195     // Hence, we map 000 to 0 and 001 to 0b00100100 = 36. The earliest value
196     // that should not map to zero with three bits is therefore 0b00001111 = 15.
197     // This ends up being (1 << (8 - 3 - 1)) - 1. We don't use 0b00011111 = 31
198     // because this would "round up" to 1 during quantization. This value is not
199     // necessarily the largest, but it is the largest that we can *guarantee*
200     // should map to zero.
201 
202     if (range >= kEndpointRangeMinValue) {
203       constexpr int cev_bits = 8;
204       const int half_max_quant_bits = std::max(0, cev_bits - num_bits - 1);
205       const int largest_cev_to_zero = (1 << half_max_quant_bits) - 1;
206       EXPECT_EQ(QuantizeCEValueToRange(largest_cev_to_zero, range), 0)
207           << " Largest CEV to zero: " << largest_cev_to_zero
208           << " Range: " << range;
209     }
210 
211     if (range <= kWeightRangeMaxValue) {
212       constexpr int weight_bits = 6;
213       const int half_max_quant_bits = std::max(0, weight_bits - num_bits - 1);
214       const int largest_weight_to_zero = (1 << half_max_quant_bits) - 1;
215       EXPECT_EQ(QuantizeWeightToRange(largest_weight_to_zero, range), 0)
216           << " Largest weight to zero: " << largest_weight_to_zero
217           << " Range: " << range;
218     }
219   }
220 }
221 
222 // Test specific quint and trit weight encodings with values that were obtained
223 // using the reference ASTC codec.
TEST(QuantizationTest,TestSpecificQuintTritPackings)224 TEST(QuantizationTest, TestSpecificQuintTritPackings) {
225   std::vector<int> vals = { 4, 6, 4, 6, 7, 5, 7, 5 };
226   std::vector<int> quantized;
227 
228   // Test a quint packing
229   std::transform(
230       vals.begin(), vals.end(), std::back_inserter(quantized),
231       std::bind(UnquantizeWeightFromRange, std::placeholders::_1, 9));
232   const std::vector<int> quintExpected = {14, 21, 14, 21, 43, 50, 43, 50 };
233   EXPECT_EQ(quantized, quintExpected);
234 
235   // Test a trit packing
236   std::transform(
237       vals.begin(), vals.end(), quantized.begin(),
238       std::bind(UnquantizeWeightFromRange, std::placeholders::_1, 11));
239   const std::vector<int> tritExpected = { 5, 23, 5, 23, 41, 59, 41, 59 };
240   EXPECT_EQ(quantized, tritExpected);
241 }
242 
243 // Make sure that we properly die when we pass in values below the minimum
244 // allowed ranges for our quantization intervals.
TEST(QuantizationDeathTest,TestInvalidMinRange)245 TEST(QuantizationDeathTest, TestInvalidMinRange) {
246   for (int i = 0; i < kEndpointRangeMinValue; ++i) {
247     EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, i), "");
248     EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, i), "");
249   }
250 
251   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, 0), "");
252   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, 0), "");
253 }
254 
255 // Make sure that we properly die when we pass in bogus values.
TEST(QuantizationDeathTest,TestOutOfRange)256 TEST(QuantizationDeathTest, TestOutOfRange) {
257   EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(-1, 10), "");
258   EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(256, 7), "");
259   EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(10000, 17), "");
260 
261   EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(-1, 10), "");
262   EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(8, 7), "");
263   EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(-1000, 17), "");
264 
265   EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, -7), "");
266   EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, -17), "");
267 
268   EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, 257), "");
269   EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, 256), "");
270 
271   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(-1, 10), "");
272   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(256, 7), "");
273   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(10000, 17), "");
274 
275   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(-1, 10), "");
276   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(8, 7), "");
277   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(-1000, 17), "");
278 
279   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, -7), "");
280   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, -17), "");
281 
282   EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, 32), "");
283   EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, 64), "");
284 }
285 
286 }  // namespace
287 
288 }  // namespace astc_codec
289