// Parallel replay of a learned Spatial Set-BPE vocabulary over action cells. #include #include #include #include #include #include #include #include #ifdef _OPENMP #include #endif namespace py = pybind11; namespace { struct Replay { int32_t dimension; int32_t vocab_size; std::vector offsets; std::vector rule; std::vector anchor; int32_t child(int32_t left, int32_t right) const { if (left > right) std::swap(left, right); return rule[static_cast(left) * vocab_size + right]; } std::vector encode(const int32_t* code) const { std::vector active; active.reserve(dimension); for (int32_t axis = 0; axis < dimension; ++axis) { if (code[axis] < 0) continue; active.push_back(offsets[axis] + code[axis]); } using Candidate = std::tuple; std::priority_queue, std::greater> heap; auto offer = [&](int32_t left, int32_t right) { const int32_t value = child(left, right); if (value >= 0) heap.emplace(value, std::min(left, right), std::max(left, right)); }; for (int32_t a = 0; a < static_cast(active.size()); ++a) { for (int32_t b = a + 1; b < static_cast(active.size()); ++b) { offer(active[a], active[b]); } } while (!heap.empty()) { const auto [child_token, left, right] = heap.top(); heap.pop(); auto left_it = std::find(active.begin(), active.end(), left); auto right_it = std::find(active.begin(), active.end(), right); if (left_it == active.end() || right_it == active.end()) continue; *left_it = child_token; active.erase(right_it); for (const int32_t other : active) { if (other != child_token) offer(child_token, other); } } std::sort(active.begin(), active.end(), [&](int32_t left, int32_t right) { if (anchor[left] != anchor[right]) return anchor[left] < anchor[right]; return left < right; }); return active; } }; } // namespace py::tuple spatial_encode_instances( const py::array_t& codes, const py::array_t& row_anchors, const std::vector& bins, const py::array_t& merges, int threads) { if (codes.ndim() != 2 || row_anchors.ndim() != 1 || row_anchors.shape(0) != codes.shape(0) || codes.shape(1) != static_cast(bins.size()) || merges.ndim() != 2 || merges.shape(1) != 2) { throw std::invalid_argument("invalid spatial replay inputs"); } Replay replay; replay.dimension = static_cast(bins.size()); replay.offsets.assign(replay.dimension + 1, 0); for (int32_t axis = 0; axis < replay.dimension; ++axis) { replay.offsets[axis + 1] = replay.offsets[axis] + bins[axis]; } const int32_t atoms = replay.offsets.back(); replay.vocab_size = atoms + static_cast(merges.shape(0)); replay.rule.assign(static_cast(replay.vocab_size) * replay.vocab_size, -1); replay.anchor.assign(replay.vocab_size, -1); for (int32_t axis = 0; axis < replay.dimension; ++axis) { for (int32_t token = replay.offsets[axis]; token < replay.offsets[axis + 1]; ++token) { replay.anchor[token] = axis; } } auto rules = merges.unchecked<2>(); for (int32_t index = 0; index < merges.shape(0); ++index) { const int32_t left = rules(index, 0), right = rules(index, 1), child = atoms + index; if (left < 0 || right < 0 || left >= child || right >= child) { throw std::invalid_argument("invalid spatial merge rule"); } replay.rule[static_cast(std::min(left, right)) * replay.vocab_size + std::max(left, right)] = child; replay.anchor[child] = std::min(replay.anchor[left], replay.anchor[right]); } const int64_t rows = codes.shape(0); std::vector counts(rows); const int32_t* source = codes.data(); for (int64_t row = 0; row < rows; ++row) { int32_t active = 0; for (int32_t axis = 0; axis < replay.dimension; ++axis) { const int32_t value = source[row * replay.dimension + axis]; if (value < -1 || value >= bins[axis]) { throw std::invalid_argument("a cell index is outside its coordinate's bin count"); } active += value >= 0; } if (active == 0) throw std::invalid_argument("every row needs an active coordinate"); } #ifndef _OPENMP (void)threads; #endif { py::gil_scoped_release release; #ifdef _OPENMP #pragma omp parallel for schedule(static) num_threads(threads > 0 ? threads : omp_get_max_threads()) #endif for (int64_t row = 0; row < rows; ++row) { counts[row] = static_cast( replay.encode(source + row * replay.dimension).size()); } } std::vector offsets(rows + 1, 0); for (int64_t row = 0; row < rows; ++row) offsets[row + 1] = offsets[row] + counts[row]; py::array_t tokens(offsets.back()); py::array_t anchors(offsets.back()); int32_t* output_tokens = tokens.mutable_data(); int64_t* output_anchors = anchors.mutable_data(); const int64_t* input_anchors = row_anchors.data(); { py::gil_scoped_release release; #ifdef _OPENMP #pragma omp parallel for schedule(static) num_threads(threads > 0 ? threads : omp_get_max_threads()) #endif for (int64_t row = 0; row < rows; ++row) { const auto encoded = replay.encode(source + row * replay.dimension); const int64_t begin = offsets[row]; for (int32_t index = 0; index < static_cast(encoded.size()); ++index) { output_tokens[begin + index] = encoded[index]; output_anchors[begin + index] = input_anchors[row]; } } } return py::make_tuple(tokens, anchors); }