2018-08-26 00:08:30 +08:00
|
|
|
// (C) Copyright 2017, Google Inc.
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-08-24 21:07:48 +08:00
|
|
|
|
2018-08-26 00:08:30 +08:00
|
|
|
#include <cmath>
|
|
|
|
#include <cstdio>
|
2018-08-24 21:07:48 +08:00
|
|
|
#include <string>
|
2018-08-26 00:08:30 +08:00
|
|
|
|
|
|
|
#include "indexmapbidi.h"
|
|
|
|
|
|
|
|
#include "include_gunit.h"
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
|
|
const int kPrimeLimit = 1000;
|
|
|
|
|
2020-12-27 17:41:48 +08:00
|
|
|
namespace tesseract {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
|
|
class IndexMapBiDiTest : public testing::Test {
|
2021-03-13 05:06:34 +08:00
|
|
|
protected:
|
2019-05-17 00:12:06 +08:00
|
|
|
void SetUp() {
|
|
|
|
std::locale::global(std::locale(""));
|
2020-12-31 01:17:58 +08:00
|
|
|
file::MakeTmpdir();
|
2019-05-17 00:12:06 +08:00
|
|
|
}
|
|
|
|
|
2021-03-13 05:06:34 +08:00
|
|
|
public:
|
|
|
|
std::string OutputNameToPath(const std::string &name) {
|
2018-08-24 21:07:48 +08:00
|
|
|
return file::JoinPath(FLAGS_test_tmpdir, name);
|
|
|
|
}
|
2018-12-11 01:52:47 +08:00
|
|
|
// Computes primes up to kPrimeLimit, using the sieve of Eratosthenes.
|
2021-03-13 05:06:34 +08:00
|
|
|
void ComputePrimes(IndexMapBiDi *map) {
|
2018-08-24 21:07:48 +08:00
|
|
|
map->Init(kPrimeLimit + 1, false);
|
|
|
|
map->SetMap(2, true);
|
|
|
|
// Set all the odds to true.
|
2021-03-13 05:06:34 +08:00
|
|
|
for (int i = 3; i <= kPrimeLimit; i += 2)
|
|
|
|
map->SetMap(i, true);
|
2018-08-24 21:07:48 +08:00
|
|
|
int factor_limit = static_cast<int>(sqrt(1.0 + kPrimeLimit));
|
|
|
|
for (int f = 3; f <= factor_limit; f += 2) {
|
|
|
|
if (map->SparseToCompact(f) >= 0) {
|
2021-03-13 05:06:34 +08:00
|
|
|
for (int m = 2; m * f <= kPrimeLimit; ++m)
|
|
|
|
map->SetMap(f * m, false);
|
2018-08-24 21:07:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
map->Setup();
|
|
|
|
}
|
|
|
|
|
2021-03-13 05:06:34 +08:00
|
|
|
void TestPrimes(const IndexMap &map) {
|
2018-08-24 21:07:48 +08:00
|
|
|
// Now all primes are mapped in the sparse map to their index.
|
|
|
|
// According to Wikipedia, the 168th prime is 997, and it has compact
|
|
|
|
// index 167 because we are indexing from 0.
|
|
|
|
EXPECT_EQ(167, map.SparseToCompact(997));
|
|
|
|
EXPECT_EQ(997, map.CompactToSparse(167));
|
|
|
|
// 995, 996, 998, 999 are not prime.
|
|
|
|
EXPECT_EQ(-1, map.SparseToCompact(995));
|
|
|
|
EXPECT_EQ(-1, map.SparseToCompact(996));
|
|
|
|
EXPECT_EQ(-1, map.SparseToCompact(998));
|
|
|
|
EXPECT_EQ(-1, map.SparseToCompact(999));
|
|
|
|
// The 167th prime is 991.
|
|
|
|
EXPECT_EQ(991, map.CompactToSparse(166));
|
|
|
|
// There are 168 primes in 0..1000.
|
|
|
|
EXPECT_EQ(168, map.CompactSize());
|
|
|
|
EXPECT_EQ(kPrimeLimit + 1, map.SparseSize());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-11 01:52:47 +08:00
|
|
|
// Tests the sieve of Eratosthenes as a way of testing setup.
|
2018-08-24 21:07:48 +08:00
|
|
|
TEST_F(IndexMapBiDiTest, Primes) {
|
|
|
|
IndexMapBiDi map;
|
|
|
|
ComputePrimes(&map);
|
|
|
|
TestPrimes(map);
|
|
|
|
// It still works if we assign it to another.
|
|
|
|
IndexMapBiDi map2;
|
|
|
|
map2.CopyFrom(map);
|
|
|
|
TestPrimes(map2);
|
|
|
|
// Or if we assign it to a base class.
|
|
|
|
IndexMap base_map;
|
|
|
|
base_map.CopyFrom(map);
|
|
|
|
TestPrimes(base_map);
|
|
|
|
// Test file i/o too.
|
2018-08-26 00:08:30 +08:00
|
|
|
std::string filename = OutputNameToPath("primesmap");
|
2021-03-13 05:06:34 +08:00
|
|
|
FILE *fp = fopen(filename.c_str(), "wb");
|
2018-08-24 21:07:48 +08:00
|
|
|
CHECK(fp != nullptr);
|
|
|
|
EXPECT_TRUE(map.Serialize(fp));
|
|
|
|
fclose(fp);
|
|
|
|
fp = fopen(filename.c_str(), "rb");
|
|
|
|
CHECK(fp != nullptr);
|
|
|
|
IndexMapBiDi read_map;
|
|
|
|
EXPECT_TRUE(read_map.DeSerialize(false, fp));
|
|
|
|
fclose(fp);
|
|
|
|
TestPrimes(read_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests the many-to-one setup feature.
|
|
|
|
TEST_F(IndexMapBiDiTest, ManyToOne) {
|
|
|
|
// Test the example in the comment on CompleteMerges.
|
|
|
|
IndexMapBiDi map;
|
|
|
|
map.Init(13, false);
|
|
|
|
map.SetMap(2, true);
|
|
|
|
map.SetMap(4, true);
|
|
|
|
map.SetMap(7, true);
|
|
|
|
map.SetMap(9, true);
|
|
|
|
map.SetMap(11, true);
|
|
|
|
map.Setup();
|
|
|
|
map.Merge(map.SparseToCompact(2), map.SparseToCompact(9));
|
|
|
|
map.Merge(map.SparseToCompact(4), map.SparseToCompact(11));
|
|
|
|
map.CompleteMerges();
|
|
|
|
EXPECT_EQ(3, map.CompactSize());
|
|
|
|
EXPECT_EQ(13, map.SparseSize());
|
|
|
|
EXPECT_EQ(1, map.SparseToCompact(4));
|
|
|
|
EXPECT_EQ(4, map.CompactToSparse(1));
|
|
|
|
EXPECT_EQ(1, map.SparseToCompact(11));
|
|
|
|
}
|
|
|
|
|
2021-03-13 05:06:34 +08:00
|
|
|
} // namespace tesseract
|