gdsdiff 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gdsdiff/__init__.py +148 -0
- gdsdiff/__main__.py +7 -0
- gdsdiff/_environment.py +12 -0
- gdsdiff/_version.py +34 -0
- gdsdiff/acceptance_evidence.py +530 -0
- gdsdiff/api.py +2955 -0
- gdsdiff/backends/__init__.py +26 -0
- gdsdiff/backends/base.py +77 -0
- gdsdiff/backends/boundary_loop_ctypes.py +191 -0
- gdsdiff/backends/cpu.py +20 -0
- gdsdiff/backends/cpu_ctypes.py +255 -0
- gdsdiff/backends/cuda.py +40 -0
- gdsdiff/backends/cuda_ctypes.py +1297 -0
- gdsdiff/backends/exact.py +424 -0
- gdsdiff/backends/geometry_ctypes.py +252 -0
- gdsdiff/backends/identity.py +53 -0
- gdsdiff/backends/metal.py +198 -0
- gdsdiff/backends/metal_ctypes.py +866 -0
- gdsdiff/backends/polygon_extract_ctypes.py +233 -0
- gdsdiff/backends/structural_ctypes.py +130 -0
- gdsdiff/boundary_loops.py +616 -0
- gdsdiff/cache.py +544 -0
- gdsdiff/canonicalize.py +176 -0
- gdsdiff/cli.py +352 -0
- gdsdiff/config.py +257 -0
- gdsdiff/cuda_setup.py +174 -0
- gdsdiff/design_history.py +65 -0
- gdsdiff/diagnostics.py +42 -0
- gdsdiff/diff_gds.py +66 -0
- gdsdiff/exact_diff_markdown.py +979 -0
- gdsdiff/exact_oracle.py +649 -0
- gdsdiff/extract.py +376 -0
- gdsdiff/gds_metadata.py +43 -0
- gdsdiff/geometry.py +112 -0
- gdsdiff/grid.py +143 -0
- gdsdiff/hierarchy.py +215 -0
- gdsdiff/hierarchy_extract.py +263 -0
- gdsdiff/inventory.py +153 -0
- gdsdiff/multiprocessing_support.py +39 -0
- gdsdiff/native.py +135 -0
- gdsdiff/native_cache.py +265 -0
- gdsdiff/native_src/cpu_prefilter.cpp +349 -0
- gdsdiff/native_src/gds_boundary_loops.cpp +505 -0
- gdsdiff/native_src/gds_geometry_scan.cpp +601 -0
- gdsdiff/native_src/gds_polygon_extract.cpp +594 -0
- gdsdiff/native_src/gds_structural_scan.cpp +335 -0
- gdsdiff/native_src/gdsdiff/CMakeLists.txt +74 -0
- gdsdiff/native_src/gdsdiff/core.cpp +191 -0
- gdsdiff/native_src/gdsdiff/core.hpp +96 -0
- gdsdiff/native_src/gdsdiff/cuda_assignment.cu +304 -0
- gdsdiff/native_src/gdsdiff/cuda_assignment.cuh +33 -0
- gdsdiff/native_src/gdsdiff/cuda_candidates.cu +133 -0
- gdsdiff/native_src/gdsdiff/cuda_candidates.cuh +17 -0
- gdsdiff/native_src/gdsdiff/cuda_ctypes.cu +4528 -0
- gdsdiff/native_src/gdsdiff/cuda_memory.cu +194 -0
- gdsdiff/native_src/gdsdiff/cuda_memory.cuh +34 -0
- gdsdiff/native_src/gdsdiff/metal_ctypes.mm +2791 -0
- gdsdiff/native_src/gdsdiff/python_bindings.cpp +21 -0
- gdsdiff/native_src/gdsdiff/test_core.cpp +93 -0
- gdsdiff/native_src/gdsdiff/test_cuda_assignment.cu +109 -0
- gdsdiff/native_src/gdsdiff/test_cuda_candidates.cu +94 -0
- gdsdiff/native_src/gdsdiff/test_cuda_memory.cu +97 -0
- gdsdiff/policy.py +305 -0
- gdsdiff/polygon_components.py +860 -0
- gdsdiff/profiles.py +152 -0
- gdsdiff/py.typed +1 -0
- gdsdiff/rect_coverage.py +384 -0
- gdsdiff/report.py +354 -0
- gdsdiff/schemas/gdsdiff_report-v1.schema.json +92 -0
- gdsdiff/semantics.py +75 -0
- gdsdiff/source_edge_diff.py +1120 -0
- gdsdiff/spatial.py +71 -0
- gdsdiff/structural_guard.py +161 -0
- gdsdiff/surplus_coverage.py +255 -0
- gdsdiff/synthetic_suite.py +1643 -0
- gdsdiff/templates.py +709 -0
- gdsdiff/tiling.py +153 -0
- gdsdiff/windowed_exact.py +270 -0
- gdsdiff/windows.py +184 -0
- gdsdiff-0.1.0.dist-info/METADATA +135 -0
- gdsdiff-0.1.0.dist-info/RECORD +85 -0
- gdsdiff-0.1.0.dist-info/WHEEL +5 -0
- gdsdiff-0.1.0.dist-info/entry_points.txt +4 -0
- gdsdiff-0.1.0.dist-info/licenses/LICENSE +674 -0
- gdsdiff-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#include "core.hpp"
|
|
2
|
+
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
|
|
5
|
+
namespace py = pybind11;
|
|
6
|
+
|
|
7
|
+
PYBIND11_MODULE(_gds_compare_core, m) {
|
|
8
|
+
m.doc() = "Optional native core helpers for gdsdiff";
|
|
9
|
+
m.def("floor_div", &gdsdiff::floor_div, py::arg("value"), py::arg("divisor"));
|
|
10
|
+
m.def(
|
|
11
|
+
"bbox_tile_range",
|
|
12
|
+
[](std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, std::int64_t tile_size) {
|
|
13
|
+
const auto bbox = gdsdiff::bbox_tile_range(gdsdiff::BBox{x0, y0, x1, y1}, tile_size);
|
|
14
|
+
return py::make_tuple(bbox.x0, bbox.y0, bbox.x1, bbox.y1);
|
|
15
|
+
},
|
|
16
|
+
py::arg("x0"),
|
|
17
|
+
py::arg("y0"),
|
|
18
|
+
py::arg("x1"),
|
|
19
|
+
py::arg("y1"),
|
|
20
|
+
py::arg("tile_size"));
|
|
21
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#include "core.hpp"
|
|
2
|
+
|
|
3
|
+
#include <cassert>
|
|
4
|
+
#include <iostream>
|
|
5
|
+
|
|
6
|
+
using namespace gdsdiff;
|
|
7
|
+
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
PolygonRecord rect(std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, LayerSpec layer = {1, 0}) {
|
|
11
|
+
return PolygonRecord{
|
|
12
|
+
layer,
|
|
13
|
+
BBox{x0, y0, x1, y1},
|
|
14
|
+
std::vector<Point>{{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}},
|
|
15
|
+
true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
} // namespace
|
|
20
|
+
|
|
21
|
+
int main() {
|
|
22
|
+
assert(floor_div(-1, 10) == -1);
|
|
23
|
+
assert(floor_div(-10, 10) == -1);
|
|
24
|
+
assert(floor_div(-11, 10) == -2);
|
|
25
|
+
assert((bbox_tile_range(BBox{-11, -1, 10, 20}, 10) == BBox{-2, -1, 1, 2}));
|
|
26
|
+
|
|
27
|
+
const auto a = rect(0, 0, 10, 10);
|
|
28
|
+
const PolygonRecord a_rotated{
|
|
29
|
+
a.layer,
|
|
30
|
+
a.bbox,
|
|
31
|
+
std::vector<Point>{{10, 10}, {0, 10}, {0, 0}, {10, 0}},
|
|
32
|
+
true,
|
|
33
|
+
};
|
|
34
|
+
assert(canonical_blob(a.points, true) == canonical_blob(a_rotated.points, true));
|
|
35
|
+
assert(canonical_blob(a.points, false) != canonical_blob(a_rotated.points, false));
|
|
36
|
+
|
|
37
|
+
const std::vector<std::string> blobs{
|
|
38
|
+
canonical_blob(a.points, true),
|
|
39
|
+
canonical_blob(a_rotated.points, true),
|
|
40
|
+
canonical_blob(rect(20, 0, 30, 10).points, true),
|
|
41
|
+
};
|
|
42
|
+
const auto ids = intern_canonical_blobs(blobs);
|
|
43
|
+
assert(ids.size() == 3);
|
|
44
|
+
assert(ids[0] == ids[1]);
|
|
45
|
+
assert(ids[0] != ids[2]);
|
|
46
|
+
|
|
47
|
+
const auto identical = run_tile_prefilter(
|
|
48
|
+
std::vector<PolygonRecord>{rect(0, 0, 9, 9)},
|
|
49
|
+
std::vector<std::uint64_t>{7},
|
|
50
|
+
std::vector<PolygonRecord>{rect(0, 0, 9, 9)},
|
|
51
|
+
std::vector<std::uint64_t>{7},
|
|
52
|
+
TileConfig{10, 4096});
|
|
53
|
+
assert(identical.candidate_tiles.empty());
|
|
54
|
+
assert(identical.assignment_count == 2);
|
|
55
|
+
assert(identical.collapsed_pair_count == 1);
|
|
56
|
+
|
|
57
|
+
const auto changed = run_tile_prefilter(
|
|
58
|
+
std::vector<PolygonRecord>{rect(0, 0, 9, 9)},
|
|
59
|
+
std::vector<std::uint64_t>{1},
|
|
60
|
+
std::vector<PolygonRecord>{rect(20, 0, 29, 9)},
|
|
61
|
+
std::vector<std::uint64_t>{2},
|
|
62
|
+
TileConfig{10, 4096});
|
|
63
|
+
assert(changed.candidate_tiles.size() == 2);
|
|
64
|
+
assert((changed.candidate_tiles[0] == TileKey{{1, 0}, 0, 0}));
|
|
65
|
+
assert((changed.candidate_tiles[1] == TileKey{{1, 0}, 2, 0}));
|
|
66
|
+
|
|
67
|
+
const auto oversized = run_tile_prefilter(
|
|
68
|
+
std::vector<PolygonRecord>{rect(0, 0, 100, 100)},
|
|
69
|
+
std::vector<std::uint64_t>{9},
|
|
70
|
+
std::vector<PolygonRecord>{},
|
|
71
|
+
std::vector<std::uint64_t>{},
|
|
72
|
+
TileConfig{10, 4});
|
|
73
|
+
assert(oversized.candidate_tiles.empty());
|
|
74
|
+
assert(oversized.oversized_candidates.size() == 1);
|
|
75
|
+
assert(oversized.oversized_candidates[0].side_mask == kOldSide);
|
|
76
|
+
assert((oversized.oversized_candidates[0].tile_bbox == BBox{0, 0, 10, 10}));
|
|
77
|
+
|
|
78
|
+
bool length_error = false;
|
|
79
|
+
try {
|
|
80
|
+
(void)run_tile_prefilter(
|
|
81
|
+
std::vector<PolygonRecord>{rect(0, 0, 1, 1)},
|
|
82
|
+
std::vector<std::uint64_t>{},
|
|
83
|
+
std::vector<PolygonRecord>{},
|
|
84
|
+
std::vector<std::uint64_t>{},
|
|
85
|
+
TileConfig{10, 4096});
|
|
86
|
+
} catch (const std::invalid_argument&) {
|
|
87
|
+
length_error = true;
|
|
88
|
+
}
|
|
89
|
+
assert(length_error);
|
|
90
|
+
|
|
91
|
+
std::cout << "cpp core tests passed\n";
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#include "cuda_assignment.cuh"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cassert>
|
|
5
|
+
#include <iostream>
|
|
6
|
+
#include <stdexcept>
|
|
7
|
+
|
|
8
|
+
using namespace gdsdiff;
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
PolygonRecord rect(std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, LayerSpec layer = {1, 0}) {
|
|
13
|
+
return PolygonRecord{
|
|
14
|
+
layer,
|
|
15
|
+
BBox{x0, y0, x1, y1},
|
|
16
|
+
std::vector<Point>{{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}},
|
|
17
|
+
true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
std::vector<TileAssignment> cpu_assignments(
|
|
22
|
+
const std::vector<PolygonRecord>& polygons,
|
|
23
|
+
const std::vector<std::uint64_t>& ids,
|
|
24
|
+
std::uint8_t side,
|
|
25
|
+
const TileConfig& config,
|
|
26
|
+
std::vector<OversizedPolygon>* oversized) {
|
|
27
|
+
std::vector<TileAssignment> assignments;
|
|
28
|
+
for (std::size_t i = 0; i < polygons.size(); ++i) {
|
|
29
|
+
const auto range = bbox_tile_range(polygons[i].bbox, config.tile_size);
|
|
30
|
+
const std::uint64_t span_x = static_cast<std::uint64_t>(range.x1 - range.x0 + 1);
|
|
31
|
+
const std::uint64_t span_y = static_cast<std::uint64_t>(range.y1 - range.y0 + 1);
|
|
32
|
+
const std::uint64_t count = span_x * span_y;
|
|
33
|
+
if (count > config.max_tiles_per_polygon) {
|
|
34
|
+
oversized->push_back(OversizedPolygon{polygons[i].layer, ids[i], side, range});
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
for (std::int64_t tx = range.x0; tx <= range.x1; ++tx) {
|
|
38
|
+
for (std::int64_t ty = range.y0; ty <= range.y1; ++ty) {
|
|
39
|
+
assignments.push_back(TileAssignment{polygons[i].layer, tx, ty, ids[i], side});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return assignments;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void assert_matches_cpu(
|
|
47
|
+
const std::vector<PolygonRecord>& polygons,
|
|
48
|
+
const std::vector<std::uint64_t>& ids,
|
|
49
|
+
std::uint8_t side,
|
|
50
|
+
const TileConfig& config) {
|
|
51
|
+
std::vector<OversizedPolygon> expected_oversized;
|
|
52
|
+
auto expected = cpu_assignments(polygons, ids, side, config, &expected_oversized);
|
|
53
|
+
auto actual = run_cuda_assignment(polygons, ids, side, config);
|
|
54
|
+
std::sort(expected.begin(), expected.end());
|
|
55
|
+
std::sort(actual.assignments.begin(), actual.assignments.end());
|
|
56
|
+
std::sort(expected_oversized.begin(), expected_oversized.end());
|
|
57
|
+
std::sort(actual.oversized.begin(), actual.oversized.end());
|
|
58
|
+
assert(actual.assignments == expected);
|
|
59
|
+
assert(actual.oversized == expected_oversized);
|
|
60
|
+
assert(actual.total_assignment_count == expected.size());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
} // namespace
|
|
64
|
+
|
|
65
|
+
int main() {
|
|
66
|
+
assert_matches_cpu({}, {}, kOldSide, TileConfig{10, 4096});
|
|
67
|
+
assert_matches_cpu(
|
|
68
|
+
std::vector<PolygonRecord>{rect(-11, -11, -1, -1)},
|
|
69
|
+
std::vector<std::uint64_t>{1},
|
|
70
|
+
kOldSide,
|
|
71
|
+
TileConfig{10, 4096});
|
|
72
|
+
assert_matches_cpu(
|
|
73
|
+
std::vector<PolygonRecord>{rect(0, 0, 10, 10)},
|
|
74
|
+
std::vector<std::uint64_t>{2},
|
|
75
|
+
kNewSide,
|
|
76
|
+
TileConfig{10, 4096});
|
|
77
|
+
assert_matches_cpu(
|
|
78
|
+
std::vector<PolygonRecord>{rect(0, 0, 100, 100)},
|
|
79
|
+
std::vector<std::uint64_t>{3},
|
|
80
|
+
kOldSide,
|
|
81
|
+
TileConfig{10, 4});
|
|
82
|
+
|
|
83
|
+
std::vector<PolygonRecord> many;
|
|
84
|
+
std::vector<std::uint64_t> ids;
|
|
85
|
+
for (int i = 0; i < 777; ++i) {
|
|
86
|
+
many.push_back(rect(i * 3, -i, i * 3 + 11, -i + 7, LayerSpec{i % 4, i % 2}));
|
|
87
|
+
ids.push_back(static_cast<std::uint64_t>(i % 9));
|
|
88
|
+
}
|
|
89
|
+
assert_matches_cpu(many, ids, kNewSide, TileConfig{10, 4096});
|
|
90
|
+
|
|
91
|
+
bool length_error = false;
|
|
92
|
+
try {
|
|
93
|
+
(void)run_cuda_assignment(std::vector<PolygonRecord>{rect(0, 0, 1, 1)}, {}, kOldSide, TileConfig{10, 4096});
|
|
94
|
+
} catch (const std::invalid_argument&) {
|
|
95
|
+
length_error = true;
|
|
96
|
+
}
|
|
97
|
+
assert(length_error);
|
|
98
|
+
|
|
99
|
+
bool config_error = false;
|
|
100
|
+
try {
|
|
101
|
+
(void)run_cuda_assignment(std::vector<PolygonRecord>{rect(0, 0, 1, 1)}, {1}, kOldSide, TileConfig{0, 4096});
|
|
102
|
+
} catch (const std::invalid_argument&) {
|
|
103
|
+
config_error = true;
|
|
104
|
+
}
|
|
105
|
+
assert(config_error);
|
|
106
|
+
|
|
107
|
+
std::cout << "cuda assignment tests passed\n";
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#include "cuda_candidates.cuh"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cassert>
|
|
5
|
+
#include <iostream>
|
|
6
|
+
|
|
7
|
+
using namespace gdsdiff;
|
|
8
|
+
|
|
9
|
+
namespace {
|
|
10
|
+
|
|
11
|
+
PolygonRecord rect(std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, LayerSpec layer = {1, 0}) {
|
|
12
|
+
return PolygonRecord{
|
|
13
|
+
layer,
|
|
14
|
+
BBox{x0, y0, x1, y1},
|
|
15
|
+
std::vector<Point>{{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}},
|
|
16
|
+
true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
void assert_same_result(
|
|
21
|
+
const std::vector<PolygonRecord>& old_polygons,
|
|
22
|
+
const std::vector<std::uint64_t>& old_ids,
|
|
23
|
+
const std::vector<PolygonRecord>& new_polygons,
|
|
24
|
+
const std::vector<std::uint64_t>& new_ids,
|
|
25
|
+
const TileConfig& config) {
|
|
26
|
+
auto cpu = run_tile_prefilter(old_polygons, old_ids, new_polygons, new_ids, config);
|
|
27
|
+
auto cuda = run_cuda_candidate_compaction(old_polygons, old_ids, new_polygons, new_ids, config);
|
|
28
|
+
std::sort(cpu.candidate_tiles.begin(), cpu.candidate_tiles.end());
|
|
29
|
+
std::sort(cuda.candidate_tiles.begin(), cuda.candidate_tiles.end());
|
|
30
|
+
std::sort(cpu.oversized_candidates.begin(), cpu.oversized_candidates.end());
|
|
31
|
+
std::sort(cuda.oversized_candidates.begin(), cuda.oversized_candidates.end());
|
|
32
|
+
assert(cuda.candidate_tiles == cpu.candidate_tiles);
|
|
33
|
+
assert(cuda.oversized_candidates == cpu.oversized_candidates);
|
|
34
|
+
assert(cuda.assignment_count == cpu.assignment_count);
|
|
35
|
+
assert(cuda.collapsed_pair_count == cpu.collapsed_pair_count);
|
|
36
|
+
assert(cuda.oversized_matched_count == cpu.oversized_matched_count);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
} // namespace
|
|
40
|
+
|
|
41
|
+
int main() {
|
|
42
|
+
assert_same_result({}, {}, {}, {}, TileConfig{10, 4096});
|
|
43
|
+
assert_same_result(
|
|
44
|
+
{rect(0, 0, 9, 9)},
|
|
45
|
+
{1},
|
|
46
|
+
{rect(0, 0, 9, 9)},
|
|
47
|
+
{1},
|
|
48
|
+
TileConfig{10, 4096});
|
|
49
|
+
assert_same_result(
|
|
50
|
+
{rect(0, 0, 9, 9)},
|
|
51
|
+
{1},
|
|
52
|
+
{rect(20, 0, 29, 9)},
|
|
53
|
+
{2},
|
|
54
|
+
TileConfig{10, 4096});
|
|
55
|
+
assert_same_result(
|
|
56
|
+
{rect(0, 0, 9, 9), rect(0, 0, 9, 9)},
|
|
57
|
+
{5, 5},
|
|
58
|
+
{rect(0, 0, 9, 9)},
|
|
59
|
+
{5},
|
|
60
|
+
TileConfig{10, 4096});
|
|
61
|
+
assert_same_result(
|
|
62
|
+
{rect(-11, -11, -1, -1)},
|
|
63
|
+
{1},
|
|
64
|
+
{},
|
|
65
|
+
{},
|
|
66
|
+
TileConfig{10, 4096});
|
|
67
|
+
assert_same_result(
|
|
68
|
+
{rect(0, 0, 100, 100)},
|
|
69
|
+
{9},
|
|
70
|
+
{},
|
|
71
|
+
{},
|
|
72
|
+
TileConfig{10, 4});
|
|
73
|
+
assert_same_result(
|
|
74
|
+
{rect(0, 0, 100, 100)},
|
|
75
|
+
{9},
|
|
76
|
+
{rect(0, 0, 100, 100)},
|
|
77
|
+
{9},
|
|
78
|
+
TileConfig{10, 4});
|
|
79
|
+
|
|
80
|
+
std::vector<PolygonRecord> old_polygons;
|
|
81
|
+
std::vector<PolygonRecord> new_polygons;
|
|
82
|
+
std::vector<std::uint64_t> old_ids;
|
|
83
|
+
std::vector<std::uint64_t> new_ids;
|
|
84
|
+
for (int i = 0; i < 513; ++i) {
|
|
85
|
+
old_polygons.push_back(rect(i * 7 - 90, i % 17 - 40, i * 7 - 82, i % 17 - 31, LayerSpec{i % 5, i % 3}));
|
|
86
|
+
old_ids.push_back(static_cast<std::uint64_t>(i % 23));
|
|
87
|
+
new_polygons.push_back(rect(i * 7 - 88, i % 17 - 40, i * 7 - 80, i % 17 - 31, LayerSpec{i % 5, i % 3}));
|
|
88
|
+
new_ids.push_back(static_cast<std::uint64_t>((i + 1) % 23));
|
|
89
|
+
}
|
|
90
|
+
assert_same_result(old_polygons, old_ids, new_polygons, new_ids, TileConfig{16, 4096});
|
|
91
|
+
|
|
92
|
+
std::cout << "cuda candidate tests passed\n";
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#include "cuda_memory.cuh"
|
|
2
|
+
#include "cuda_candidates.cuh"
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <cassert>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
|
|
8
|
+
using namespace gdsdiff;
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
PolygonRecord rect(std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, LayerSpec layer = {1, 0}) {
|
|
13
|
+
return PolygonRecord{
|
|
14
|
+
layer,
|
|
15
|
+
BBox{x0, y0, x1, y1},
|
|
16
|
+
std::vector<Point>{{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}},
|
|
17
|
+
true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void sort_result(TilePrefilterResult& result) {
|
|
22
|
+
std::sort(result.candidate_tiles.begin(), result.candidate_tiles.end());
|
|
23
|
+
std::sort(result.oversized_candidates.begin(), result.oversized_candidates.end());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
void assert_chunked_matches(
|
|
27
|
+
const std::vector<PolygonRecord>& old_polygons,
|
|
28
|
+
const std::vector<std::uint64_t>& old_ids,
|
|
29
|
+
const std::vector<PolygonRecord>& new_polygons,
|
|
30
|
+
const std::vector<std::uint64_t>& new_ids,
|
|
31
|
+
const TileConfig& config,
|
|
32
|
+
const CudaMemoryBudget& budget,
|
|
33
|
+
bool expect_chunking) {
|
|
34
|
+
auto cpu = run_tile_prefilter(old_polygons, old_ids, new_polygons, new_ids, config);
|
|
35
|
+
auto whole_cuda = run_cuda_candidate_compaction(old_polygons, old_ids, new_polygons, new_ids, config);
|
|
36
|
+
auto chunked = run_cuda_candidate_compaction_chunked(old_polygons, old_ids, new_polygons, new_ids, config, budget);
|
|
37
|
+
sort_result(cpu);
|
|
38
|
+
sort_result(whole_cuda);
|
|
39
|
+
sort_result(chunked.prefilter);
|
|
40
|
+
assert(chunked.prefilter.candidate_tiles == cpu.candidate_tiles);
|
|
41
|
+
assert(chunked.prefilter.candidate_tiles == whole_cuda.candidate_tiles);
|
|
42
|
+
assert(chunked.prefilter.oversized_candidates == cpu.oversized_candidates);
|
|
43
|
+
assert(chunked.prefilter.oversized_candidates == whole_cuda.oversized_candidates);
|
|
44
|
+
assert(chunked.stats.chunk_count >= 1);
|
|
45
|
+
assert(chunked.stats.used_chunking == expect_chunking);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
} // namespace
|
|
49
|
+
|
|
50
|
+
int main() {
|
|
51
|
+
assert_chunked_matches({}, {}, {}, {}, TileConfig{10, 4096}, CudaMemoryBudget{64, 64}, false);
|
|
52
|
+
assert_chunked_matches(
|
|
53
|
+
{rect(0, 0, 9, 45), rect(20, 0, 29, 9, LayerSpec{2, 0})},
|
|
54
|
+
{1, 2},
|
|
55
|
+
{rect(0, 10, 9, 55), rect(25, 0, 34, 9, LayerSpec{2, 0})},
|
|
56
|
+
{3, 4},
|
|
57
|
+
TileConfig{10, 4096},
|
|
58
|
+
CudaMemoryBudget{128, 64},
|
|
59
|
+
true);
|
|
60
|
+
assert_chunked_matches(
|
|
61
|
+
{rect(0, 0, 100, 100)},
|
|
62
|
+
{9},
|
|
63
|
+
{},
|
|
64
|
+
{},
|
|
65
|
+
TileConfig{10, 4},
|
|
66
|
+
CudaMemoryBudget{64, 64},
|
|
67
|
+
false);
|
|
68
|
+
|
|
69
|
+
std::vector<PolygonRecord> old_polygons;
|
|
70
|
+
std::vector<PolygonRecord> new_polygons;
|
|
71
|
+
std::vector<std::uint64_t> old_ids;
|
|
72
|
+
std::vector<std::uint64_t> new_ids;
|
|
73
|
+
for (int i = 0; i < 160; ++i) {
|
|
74
|
+
old_polygons.push_back(rect(i - 80, i * 5 - 300, i - 71, i * 5 - 276, LayerSpec{i % 3, i % 2}));
|
|
75
|
+
old_ids.push_back(static_cast<std::uint64_t>(i % 11));
|
|
76
|
+
new_polygons.push_back(rect(i - 78, i * 5 - 298, i - 69, i * 5 - 274, LayerSpec{i % 3, i % 2}));
|
|
77
|
+
new_ids.push_back(static_cast<std::uint64_t>((i + 3) % 11));
|
|
78
|
+
}
|
|
79
|
+
assert_chunked_matches(old_polygons, old_ids, new_polygons, new_ids, TileConfig{8, 4096}, CudaMemoryBudget{512, 64}, true);
|
|
80
|
+
|
|
81
|
+
bool config_error = false;
|
|
82
|
+
try {
|
|
83
|
+
(void)run_cuda_candidate_compaction_chunked(
|
|
84
|
+
{rect(0, 0, 1, 1)},
|
|
85
|
+
{1},
|
|
86
|
+
{},
|
|
87
|
+
{},
|
|
88
|
+
TileConfig{10, 4096},
|
|
89
|
+
CudaMemoryBudget{0, 64});
|
|
90
|
+
} catch (const std::invalid_argument&) {
|
|
91
|
+
config_error = true;
|
|
92
|
+
}
|
|
93
|
+
assert(config_error);
|
|
94
|
+
|
|
95
|
+
std::cout << "cuda memory tests passed\n";
|
|
96
|
+
return 0;
|
|
97
|
+
}
|