Skip to content

Commit f57496c

Browse files
authored
Merge pull request #29 from quantumlib/main
latest changes
2 parents 93a96a8 + 17ec792 commit f57496c

File tree

8 files changed

+95
-32
lines changed

8 files changed

+95
-32
lines changed

.github/workflows/prerelease.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ jobs:
3232
strategy:
3333
fail-fast: true
3434
matrix:
35-
os: [ubuntu-24.04, macos-13]
35+
os: [ubuntu-22.04, ubuntu-24.04, macos-13, macos-14]
3636
python-version: ['3.10', '3.11', '3.12']
37-
38-
3937
steps:
4038
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
4139
- name: Set up Python
@@ -66,7 +64,11 @@ jobs:
6664
env:
6765
TARGET_PYTHON: ${{ matrix.python-version }}
6866
run: |
69-
bazel build --define TARGET_VERSION="$(python -c "print(\"py${TARGET_PYTHON}\".replace(\".\", \"\"))")" --define VERSION="$(cat version/version.txt)" :tesseract_decoder_wheel
67+
glibc_version=$(ldd --version | awk '/ldd/{print $NF}')
68+
export GLIBC_VERSION="${glibc_version//./_}"
69+
echo $GLIBC_VERSION
70+
sed "s/^MANYLINUX_VERSION.*/MANYLINUX_VERSION=\"manylinux_${GLIBC_VERSION}_x86_64.manylinux2014_x86_64\"/" BUILD -i || true
71+
bazel build --define GLIBC_VERSION=$GLIBC_VERSION --define TARGET_VERSION="$(python -c "print(\"py${TARGET_PYTHON}\".replace(\".\", \"\"))")" --define VERSION="$(cat version/version.txt)" :tesseract_decoder_wheel
7072
7173
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
7274
with:

.github/workflows/stable-release-workflow.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
strategy:
3232
fail-fast: true
3333
matrix:
34-
os: [ubuntu-24.04, macos-13]
34+
os: [ubuntu-22.04, ubuntu-24.04, macos-13, macos-14]
3535
python-version: ['3.10', '3.11', '3.12']
3636

3737
steps:
@@ -64,6 +64,10 @@ jobs:
6464
env:
6565
TARGET_PYTHON: ${{ matrix.python-version }}
6666
run: |
67+
glibc_version=$(ldd --version | awk '/ldd/{print $NF}')
68+
export GLIBC_VERSION="${glibc_version//./_}"
69+
echo $GLIBC_VERSION
70+
sed "s/^MANYLINUX_VERSION.*/MANYLINUX_VERSION=\"manylinux_${GLIBC_VERSION}_x86_64.manylinux2014_x86_64\"/" BUILD -i || true
6771
bazel build --define TARGET_VERSION="$(python -c "print(\"py${TARGET_PYTHON}\".replace(\".\", \"\"))")" --define VERSION="$(cat version/version.txt)" :tesseract_decoder_wheel
6872
6973
- uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4

BUILD

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ filegroup(
1313
visibility = ["//visibility:public"],
1414
)
1515

16+
MANYLINUX_VERSION="manylinux_2_17_x86_64.manylinux2014_x86_64"
17+
1618
py_wheel(
1719
name="tesseract_decoder_wheel",
1820
distribution = "tesseract_decoder",
@@ -26,9 +28,10 @@ py_wheel(
2628
],
2729
python_tag="$(TARGET_VERSION)",
2830
platform= select({
29-
"@platforms//os:macos": "macosx_10_13_x86_64",
31+
":macos_arm": "macosx_11_0_arm64",
32+
":macos_x86": "macosx_10_13_x86_64",
3033
"@platforms//os:windows": "win32",
31-
"@platforms//os:linux": "manylinux_2_17_x86_64.manylinux2014_x86_64",
34+
"@platforms//os:linux": MANYLINUX_VERSION,
3235
}),
3336
strip_path_prefixes = ["src"],
3437
description_file=":package_description",
@@ -37,3 +40,19 @@ py_wheel(
3740
author="The Tesseract Decoder Authors.",
3841
homepage="https://github.com/quantumlib/tesseract-decoder",
3942
)
43+
44+
config_setting(
45+
name = "macos_arm",
46+
constraint_values = [
47+
"@platforms//os:macos",
48+
"@platforms//cpu:arm64",
49+
],
50+
)
51+
52+
config_setting(
53+
name = "macos_x86",
54+
constraint_values = [
55+
"@platforms//os:macos",
56+
"@platforms//cpu:x86_64",
57+
],
58+
)

WORKSPACE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,22 @@ http_archive(
6666
urls = ["https://github.com/bazelbuild/platforms/archive/refs/tags/0.0.6.zip"],
6767
strip_prefix = "platforms-0.0.6",
6868
)
69+
70+
71+
72+
73+
BOOST_VERSION = "1.83.0"
74+
BOOST_ARCHIVE_NAME = "boost_{}".format(BOOST_VERSION.replace(".", "_"))
75+
76+
http_archive(
77+
name = "boost",
78+
urls = [
79+
"https://archives.boost.io/release/{}/source/{}.tar.gz".format(
80+
BOOST_VERSION,
81+
BOOST_ARCHIVE_NAME,
82+
)
83+
],
84+
strip_prefix = BOOST_ARCHIVE_NAME,
85+
sha256 = "c0685b68dd44cc46574cce86c4e17c0f611b15e195be9848dfd0769a0a207628",
86+
build_file = "//external:boost.BUILD",
87+
)

external/boost.BUILD

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# external/boost.BUILD
2+
package(default_visibility = ["//visibility:public"])
3+
4+
# A cc_library for the Boost headers themselves.
5+
cc_library(
6+
name = "boost_headers",
7+
hdrs = glob(["boost/**/*.hpp"]),
8+
includes = ["."],
9+
)
10+
11+
# A specific target for dynamic_bitset, which is header-only
12+
# and depends on the main headers.
13+
cc_library(
14+
name = "dynamic_bitset",
15+
deps = [":boost_headers"],
16+
)

src/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ cc_library(
121121
linkopts = OPT_LINKOPTS,
122122
deps = [
123123
":libutils",
124+
"@boost//:dynamic_bitset",
124125
],
125126
)
126127

src/tesseract.cc

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
#include "tesseract.h"
1616

1717
#include <algorithm>
18+
#include <boost/functional/hash.hpp> // For boost::hash_range
1819
#include <cassert>
20+
#include <functional> // For std::hash (though not strictly necessary here, but good practice)
1921
#include <iostream>
2022

2123
namespace {
@@ -37,6 +39,17 @@ std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
3739

3840
}; // namespace
3941

42+
namespace std {
43+
template <>
44+
struct hash<boost::dynamic_bitset<>> {
45+
size_t operator()(const boost::dynamic_bitset<>& bs) const {
46+
// Delegate to Boost's internal hash_value for dynamic_bitset
47+
// This is the correct and most efficient way.
48+
return boost::hash_value(bs);
49+
}
50+
};
51+
} // namespace std
52+
4053
std::string TesseractConfig::str() {
4154
auto& config = *this;
4255
std::stringstream ss;
@@ -73,7 +86,7 @@ double TesseractDecoder::get_detcost(
7386
ErrorCost ec;
7487
DetectorCostTuple dct;
7588

76-
for (size_t ei : d2e[d]) {
89+
for (int ei : d2e[d]) {
7790
ec = error_costs[ei];
7891
if (ec.min_cost >= min_cost) break;
7992

@@ -89,17 +102,6 @@ double TesseractDecoder::get_detcost(
89102
return min_cost + config.det_penalty;
90103
}
91104

92-
struct VectorCharHash {
93-
size_t operator()(const std::vector<char>& v) const {
94-
size_t seed = v.size();
95-
96-
for (char el : v) {
97-
seed = seed * 31 + static_cast<size_t>(el);
98-
}
99-
return seed;
100-
}
101-
};
102-
103105
TesseractDecoder::TesseractDecoder(TesseractConfig config_) : config(config_) {
104106
config.dem = common::remove_zero_probability_errors(config.dem);
105107
if (config.det_orders.empty()) {
@@ -206,7 +208,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections)
206208
}
207209

208210
void TesseractDecoder::flip_detectors_and_block_errors(
209-
size_t detector_order, const std::vector<size_t>& errors, std::vector<char>& detectors,
211+
size_t detector_order, const std::vector<size_t>& errors, boost::dynamic_bitset<>& detectors,
210212
std::vector<DetectorCostTuple>& detector_cost_tuples) const {
211213
for (size_t ei : errors) {
212214
size_t min_detector = std::numeric_limits<size_t>::max();
@@ -217,15 +219,15 @@ void TesseractDecoder::flip_detectors_and_block_errors(
217219
}
218220
}
219221

220-
for (size_t oei : d2e[min_detector]) {
222+
for (int oei : d2e[min_detector]) {
221223
detector_cost_tuples[oei].error_blocked = 1;
222224
if (!config.at_most_two_errors_per_detector && oei == ei) break;
223225
}
224226

225-
for (size_t d : edets[ei]) {
227+
for (int d : edets[ei]) {
226228
detectors[d] = !detectors[d];
227229
if (!detectors[d] && config.at_most_two_errors_per_detector) {
228-
for (size_t oei : d2e[d]) {
230+
for (int oei : d2e[d]) {
229231
detector_cost_tuples[oei].error_blocked = 1;
230232
}
231233
}
@@ -239,10 +241,9 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
239241
low_confidence_flag = false;
240242

241243
std::priority_queue<Node, std::vector<Node>, std::greater<Node>> pq;
242-
std::unordered_map<size_t, std::unordered_set<std::vector<char>, VectorCharHash>>
243-
visited_detectors;
244+
std::unordered_map<size_t, std::unordered_set<boost::dynamic_bitset<>>> visited_detectors;
244245

245-
std::vector<char> initial_detectors(num_detectors, false);
246+
boost::dynamic_bitset<> initial_detectors(num_detectors, false);
246247
std::vector<DetectorCostTuple> initial_detector_cost_tuples(num_errors);
247248

248249
for (size_t d : detections) {
@@ -266,7 +267,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
266267
size_t max_num_detectors = min_num_detectors + detector_beam;
267268

268269
std::vector<size_t> next_errors;
269-
std::vector<char> next_detectors;
270+
boost::dynamic_bitset<> next_detectors;
270271
std::vector<DetectorCostTuple> next_detector_cost_tuples;
271272

272273
pq.push({initial_cost, min_num_detectors, std::vector<size_t>()});
@@ -278,7 +279,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
278279

279280
if (node.num_detectors > max_num_detectors) continue;
280281

281-
std::vector<char> detectors = initial_detectors;
282+
boost::dynamic_bitset<> detectors = initial_detectors;
282283
std::vector<DetectorCostTuple> detector_cost_tuples(num_errors);
283284
flip_detectors_and_block_errors(detector_order, node.errors, detectors, detector_cost_tuples);
284285

@@ -363,7 +364,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
363364
size_t prev_ei = std::numeric_limits<size_t>::max();
364365
std::vector<double> detector_cost_cache(num_detectors, -1);
365366

366-
for (size_t ei : d2e[min_detector]) {
367+
for (int ei : d2e[min_detector]) {
367368
if (detector_cost_tuples[ei].error_blocked) continue;
368369

369370
if (prev_ei != std::numeric_limits<size_t>::max()) {
@@ -398,7 +399,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
398399
}
399400

400401
if (!next_detectors[d] && config.at_most_two_errors_per_detector) {
401-
for (size_t oei : d2e[d]) {
402+
for (int oei : d2e[d]) {
402403
next_detector_cost_tuples[oei].error_blocked =
403404
next_detector_cost_tuples[oei].error_blocked == 1
404405
? 1
@@ -426,7 +427,7 @@ void TesseractDecoder::decode_to_errors(const std::vector<uint64_t>& detections,
426427
}
427428
}
428429

429-
for (size_t od : eneighbors[ei]) {
430+
for (int od : eneighbors[ei]) {
430431
if (!detectors[od] || !next_detectors[od]) continue;
431432
if (detector_cost_cache[od] == -1) {
432433
detector_cost_cache[od] = get_detcost(od, detector_cost_tuples);

src/tesseract.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef TESSERACT_DECODER_H
1616
#define TESSERACT_DECODER_H
1717

18+
#include <boost/dynamic_bitset.hpp>
1819
#include <queue>
1920
#include <string>
2021
#include <unordered_map>
@@ -101,7 +102,7 @@ struct TesseractDecoder {
101102
void initialize_structures(size_t num_detectors);
102103
double get_detcost(size_t d, const std::vector<DetectorCostTuple>& detector_cost_tuples) const;
103104
void flip_detectors_and_block_errors(size_t detector_order, const std::vector<size_t>& errors,
104-
std::vector<char>& detectors,
105+
boost::dynamic_bitset<>& detectors,
105106
std::vector<DetectorCostTuple>& detector_cost_tuples) const;
106107
};
107108

0 commit comments

Comments
 (0)