Instructions to use ZibinDong/ActionCodec2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ZibinDong/ActionCodec2 with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("ZibinDong/ActionCodec2", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 18,508 Bytes
1bfc3f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | // Optional lossless fixed-vocabulary packing for the native Set-BPE encoder.
#pragma once
#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <stdexcept>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
namespace ac2pack {
using Instance = std::tuple<int64_t, int64_t, int64_t>;
using Cover = std::array<uint64_t, 4>;
struct CoverHash {
size_t operator()(const Cover& value) const {
size_t hash = 0;
for (uint64_t word : value) hash ^= std::hash<uint64_t>{}(word) +
0x9e3779b97f4a7c15ULL + (hash << 6) + (hash >> 2);
return hash;
}
};
struct Placement {
Cover cells{};
int64_t token;
int anchor, count;
};
struct Requirement { int offset; uint64_t mask, key; };
using MatchCache = std::array<std::unordered_map<uint64_t, std::vector<int64_t>>, 8>;
inline int first_free(const Cover& cover) {
for (int word = 0; word < 4; ++word)
if (~cover[word]) return word * 64 + __builtin_ctzll(~cover[word]);
return 256;
}
inline int free_count(const Cover& cover) {
int count = 0;
for (uint64_t word : cover) count += __builtin_popcountll(~word);
return count;
}
inline bool overlaps(const Cover& a, const Cover& b) {
for (int word = 0; word < 4; ++word) if (a[word] & b[word]) return true;
return false;
}
inline Cover unite(Cover a, const Cover& b) {
for (int word = 0; word < 4; ++word) a[word] |= b[word];
return a;
}
class Search {
public:
Search(const std::vector<int64_t>& bins, const std::vector<uint64_t>& support,
const std::vector<int64_t>& expansion,
const std::vector<std::vector<std::pair<int64_t, int64_t>>>& patterns,
const std::vector<int64_t>& roots)
: bins_(bins), width_(bins.size()), spatial_size_(support.size()),
support_(support), patterns_(patterns) {
if (width_ > 8) throw std::invalid_argument("packing search supports at most eight slots");
for (int64_t count : bins)
if (count > 255) throw std::invalid_argument("packing search supports at most 255 bins per slot");
keys_.resize(spatial_size_);
anchors_.resize(patterns.size());
spans_.resize(patterns.size(), 1);
counts_.resize(patterns.size());
for (int64_t id = 0; id < spatial_size_; ++id) {
for (int d = 0; d < width_; ++d) {
const int64_t value = expansion[id * width_ + d];
if (value >= 0) keys_[id] |= uint64_t(value + 1) << (8 * d);
}
lookup_.emplace(keys_[id], id);
}
temporal_by_root_.resize(spatial_size_);
for (size_t id = 0; id < patterns.size(); ++id) {
anchors_[id] = __builtin_ctzll(support[roots[id]]);
int count = 0;
for (auto [time, sid] : patterns[id]) {
count += __builtin_popcountll(support[sid]);
spans_[id] = std::max(spans_[id], int(time + 1));
}
max_cells_ = std::max(max_cells_, count);
counts_[id] = count;
if (id >= static_cast<size_t>(spatial_size_))
temporal_by_root_[lookup_.at(keys_[roots[id]])].push_back(id);
}
byte_masks_.resize(1 << width_);
for (int mask = 1; mask < (1 << width_); ++mask) {
const int d = __builtin_ctz(mask);
byte_masks_[mask] = byte_masks_[mask ^ (1 << d)] | (uint64_t{255} << (8 * d));
}
prepare_spatial_trie();
prepare_patterns();
}
std::vector<int64_t> apply(const int64_t* cells, int64_t steps,
const std::vector<int64_t>& original, bool spatial, bool temporal, int window, int beam) const {
if (!temporal) return spatial ? repack(cells, steps, original) : original;
auto result = local_repack(cells, steps, original, window, beam);
return spatial ? repack(cells, steps, result) : result;
}
private:
struct TrieNode { std::vector<int32_t> children; int64_t token = -1; };
int32_t trie_node(int dimension) {
const auto index = static_cast<int32_t>(trie_.size());
trie_.emplace_back();
if (dimension < width_) trie_.back().children.assign(bins_[dimension] + 1, -1);
return index;
}
void prepare_spatial_trie() {
for (int d = 0; d < width_; ++d) trie_roots_[d].assign(bins_[d] + 1, -1);
for (int64_t sid = 0; sid < spatial_size_; ++sid) {
if (lookup_.at(keys_[sid]) != sid) continue;
const int root = anchors_[sid], value = (keys_[sid] >> (8 * root)) & 255;
int32_t node = trie_roots_[root][value];
if (node < 0) {
node = trie_node(root + 1);
trie_roots_[root][value] = node;
}
for (int d = root + 1; d < width_; ++d) {
const int cell = (keys_[sid] >> (8 * d)) & 255;
int32_t child = trie_[node].children[cell];
if (child < 0) {
child = trie_node(d + 1);
trie_[node].children[cell] = child;
}
node = child;
}
trie_[node].token = sid;
}
}
void query_spatial_trie(int32_t node, int dimension, uint64_t row,
std::vector<int64_t>& result) const {
if (node < 0) return;
if (dimension == width_) { result.push_back(trie_[node].token); return; }
query_spatial_trie(trie_[node].children[0], dimension + 1, row, result);
const int value = (row >> (8 * dimension)) & 255;
if (value) query_spatial_trie(trie_[node].children[value], dimension + 1, row, result);
}
void prepare_patterns() {
relative_.resize(patterns_.size());
requirements_.resize(patterns_.size());
for (size_t token = 0; token < patterns_.size(); ++token) {
if (spans_[token] * width_ > 256) continue;
std::vector<Requirement> rows(spans_[token], Requirement{0, 0, 0});
for (auto [offset, sid] : patterns_[token]) {
rows[offset].offset = offset;
rows[offset].mask |= byte_masks_[support_[sid]];
rows[offset].key |= keys_[sid];
uint64_t support = support_[sid];
while (support) {
const int d = __builtin_ctzll(support); support &= support - 1;
const int bit = offset * width_ + d;
relative_[token][bit / 64] |= uint64_t{1} << (bit % 64);
}
}
for (const auto& row : rows) if (row.mask) requirements_[token].push_back(row);
}
}
uint64_t row_key(const int64_t* row) const {
uint64_t key = 0;
for (int d = 0; d < width_; ++d)
if (row[d] >= 0) key |= uint64_t(row[d] + 1) << (8 * d);
return key;
}
std::vector<int64_t> matching_spatial(uint64_t row, int dim) const {
std::vector<int64_t> result;
const int value = (row >> (8 * dim)) & 255;
if (value) query_spatial_trie(trie_roots_[dim][value], dim + 1, row, result);
return result;
}
bool placement(int64_t token, int anchor, const std::vector<uint64_t>& rows,
const Cover& fixed, Placement& out) const {
if (anchor + spans_[token] > static_cast<int>(rows.size())) return false;
for (const auto& req : requirements_[token])
if ((rows[anchor + req.offset] & req.mask) != req.key) return false;
out = Placement{}; out.token = token; out.anchor = anchor; out.count = counts_[token];
const int start = anchor * width_, word = start / 64, shift = start % 64;
const int words = (spans_[token] * width_ + 63) / 64;
for (int i = 0; i < words && word + i < 4; ++i) {
out.cells[word + i] |= relative_[token][i] << shift;
if (shift && word + i + 1 < 4)
out.cells[word + i + 1] |= relative_[token][i] >> (64 - shift);
}
return !overlaps(out.cells, fixed);
}
std::vector<Placement> candidates(
int root, const std::vector<uint64_t>& rows, const Cover& fixed,
MatchCache& cache) const {
std::vector<Placement> result;
const int time = root / width_, dim = root % width_;
auto& table = cache[dim];
auto found = table.find(rows[time]);
if (found == table.end())
found = table.emplace(rows[time], matching_spatial(rows[time], dim)).first;
for (int64_t sid : found->second) {
Placement offer;
if (placement(sid, time, rows, fixed, offer)) result.push_back(offer);
for (int64_t token : temporal_by_root_[sid])
if (placement(token, time, rows, fixed, offer)) result.push_back(offer);
}
std::sort(result.begin(), result.end(), [](const Placement& a, const Placement& b) {
return std::make_pair(-a.count, a.token) < std::make_pair(-b.count, b.token);
});
return result;
}
using Options = std::function<const std::vector<Placement>&(int)>;
std::vector<Instance> greedy_cover(const Options& options, Cover occupied, int bound) const {
std::vector<Instance> result;
while (first_free(occupied) != 256 && static_cast<int>(result.size()) + 1 < bound) {
const auto& offers = options(first_free(occupied));
auto choice = std::find_if(offers.begin(), offers.end(), [&](const Placement& offer) {
return !overlaps(occupied, offer.cells);
});
if (choice == offers.end()) return {};
result.emplace_back(choice->anchor, anchors_[choice->token], choice->token);
occupied = unite(occupied, choice->cells);
}
return first_free(occupied) == 256 ? result : std::vector<Instance>{};
}
std::vector<Instance> beam_cover(const Options& options,
const Cover& fixed, int bound, int beam) const {
if (beam == 1) return greedy_cover(options, fixed, bound);
struct Node { Cover covered; int parent; int64_t token; int anchor, remaining, root; };
std::vector<Node> arena{{fixed, -1, -1, -1, free_count(fixed), first_free(fixed)}};
arena.reserve(beam * bound + 1);
std::vector<int> frontier{0};
frontier.reserve(beam);
std::array<Node, 64> next;
auto better = [](const Node& a, const Node& b) {
if (a.remaining != b.remaining) return a.remaining < b.remaining;
return a.root != b.root ? a.root > b.root : a.covered < b.covered;
};
for (int depth = 0; depth + 1 < bound && !frontier.empty(); ++depth) {
int keep = 0;
for (int index : frontier) {
for (const auto& offer : options(arena[index].root)) {
if (overlaps(arena[index].covered, offer.cells)) continue;
Cover covered = unite(arena[index].covered, offer.cells);
const int remaining = arena[index].remaining - offer.count;
if (!remaining) {
std::vector<Instance> result{{offer.anchor, anchors_[offer.token], offer.token}};
for (int p = index; arena[p].parent >= 0; p = arena[p].parent)
result.emplace_back(arena[p].anchor, anchors_[arena[p].token], arena[p].token);
std::reverse(result.begin(), result.end());
return result;
}
if (keep == beam && remaining > next[keep - 1].remaining) continue;
Node node{covered, index, offer.token, offer.anchor, remaining, first_free(covered)};
if (keep == beam && !better(node, next[keep - 1])) continue;
bool duplicate = false;
for (int i = 0; i < keep; ++i) if (covered == next[i].covered) { duplicate = true; break; }
if (duplicate) continue;
int position = keep < beam ? keep++ : keep - 1;
while (position && better(node, next[position - 1])) {
next[position] = next[position - 1]; --position;
}
next[position] = node;
}
}
frontier.clear();
for (int i = 0; i < keep; ++i) {
frontier.push_back(arena.size());
arena.push_back(std::move(next[i]));
}
}
return {};
}
std::vector<int64_t> local_repack(const int64_t* cells, int64_t steps,
const std::vector<int64_t>& stream, int window, int beam) const {
uint64_t full = 0;
for (int d = 0; d < width_; ++d) if (cells[d] >= 0) full |= uint64_t{1} << d;
std::vector<uint64_t> coverage(steps, 0), fixed(steps, 0);
std::vector<std::vector<Instance>> blocks((steps + window - 1) / window);
std::vector<Instance> result;
int64_t front = 0;
for (int64_t token : stream) {
while (front < steps && coverage[front] == full) ++front;
const bool crossing = front / window != (front + spans_[token] - 1) / window;
Instance instance{front, anchors_[token], token};
if (crossing) result.push_back(instance);
else blocks[front / window].push_back(instance);
for (auto [offset, sid] : patterns_[token]) {
coverage[front + offset] |= support_[sid];
if (crossing) fixed[front + offset] |= support_[sid];
}
}
MatchCache cache;
for (size_t block = 0; block < blocks.size(); ++block) {
const int start = block * window, length = std::min<int64_t>(window, steps - start);
Cover occupied; occupied.fill(~uint64_t{0});
std::vector<uint64_t> rows(length);
for (int t = 0; t < length; ++t) {
rows[t] = row_key(cells + (start + t) * width_);
for (int d = 0; d < width_; ++d) {
const int bit = t * width_ + d;
if ((full & (uint64_t{1} << d)) && !(fixed[start + t] & (uint64_t{1} << d)))
occupied[bit / 64] &= ~(uint64_t{1} << (bit % 64));
}
}
std::vector<Instance> improved;
const int bound = blocks[block].size();
if ((free_count(occupied) + max_cells_ - 1) / max_cells_ < bound) {
std::vector<std::vector<Placement>> options(length * width_);
std::vector<char> ready(length * width_, 0);
auto get_options = [&](int root) -> const std::vector<Placement>& {
if (!ready[root]) {
options[root] = candidates(root, rows, occupied, cache);
ready[root] = 1;
}
return options[root];
};
improved = beam_cover(get_options, occupied, bound, beam);
}
if (improved.empty()) result.insert(result.end(), blocks[block].begin(), blocks[block].end());
else for (auto [time, root, token] : improved) result.emplace_back(start + time, root, token);
for (auto& table : cache) if (table.size() > 4096) table.clear();
}
std::sort(result.begin(), result.end());
std::vector<int64_t> tokens;
for (auto [time, root, token] : result) tokens.push_back(token);
if (tokens.size() > stream.size()) throw std::runtime_error("local packing regressed");
return tokens;
}
std::vector<int64_t> optimal(uint64_t row, int mask,
const std::vector<int64_t>& incumbent) const {
if (incumbent.size() < 2) return incumbent;
std::array<int64_t, 256> matched;
matched.fill(-2);
auto match = [&](int subset) {
int64_t& token = matched[subset];
if (token == -2) {
const auto found = lookup_.find(row & byte_masks_[subset]);
token = found == lookup_.end() ? -1 : found->second;
}
return token;
};
if (int64_t token = match(mask); token >= 0) return {token};
if (incumbent.size() == 2) return incumbent;
const int bit = mask & -mask;
for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {
if (!(sub & bit)) continue;
const int64_t left = match(sub), right = match(mask ^ sub);
if (left >= 0 && right >= 0) return {left, right};
}
if (incumbent.size() == 3) return incumbent;
std::array<int, 256> costs, choices;
costs.fill(99); choices.fill(0); costs[0] = 0;
std::function<int(int)> solve = [&](int remaining) {
if (costs[remaining] != 99) return costs[remaining];
int best = 98;
const int first = remaining & -remaining;
for (int sub = remaining; sub; sub = (sub - 1) & remaining) {
if (!(sub & first) || match(sub) < 0) continue;
const int cost = 1 + solve(remaining ^ sub);
if (cost < best) { best = cost; choices[remaining] = sub; }
}
return costs[remaining] = best;
};
if (solve(mask) >= static_cast<int>(incumbent.size())) return incumbent;
std::vector<int64_t> result;
for (int remaining = mask; remaining; remaining ^= choices[remaining])
result.push_back(match(choices[remaining]));
return result;
}
std::vector<int64_t> repack(const int64_t* cells, int64_t steps,
const std::vector<int64_t>& stream) const {
uint64_t full = 0;
for (int d = 0; d < width_; ++d) if (cells[d] >= 0) full |= uint64_t{1} << d;
std::vector<uint64_t> covered(steps, 0), fixed(steps, 0);
std::vector<std::vector<int64_t>> old_spatial(steps), temporal(steps);
int64_t front = 0;
for (int64_t token : stream) {
while (front < steps && covered[front] == full) ++front;
if (front == steps || token < 0 || token >= static_cast<int64_t>(patterns_.size()) ||
anchors_[token] != __builtin_ctzll(full & ~covered[front]))
throw std::invalid_argument("invalid original token stream");
const bool frozen = token >= spatial_size_;
(frozen ? temporal[front] : old_spatial[front]).push_back(token);
for (auto [offset, id] : patterns_[token]) {
if (front + offset >= steps || (covered[front + offset] & support_[id]))
throw std::invalid_argument("invalid original token coverage");
covered[front + offset] |= support_[id];
if (frozen) fixed[front + offset] |= support_[id];
}
}
std::vector<int64_t> result;
result.reserve(stream.size());
for (int64_t time = 0; time < steps; ++time) {
if (covered[time] != full) throw std::invalid_argument("incomplete original stream");
auto tokens = optimal(row_key(cells + time * width_), full & ~fixed[time], old_spatial[time]);
tokens.insert(tokens.end(), temporal[time].begin(), temporal[time].end());
std::sort(tokens.begin(), tokens.end(), [&](int64_t a, int64_t b) {
return std::make_pair(anchors_[a], a) < std::make_pair(anchors_[b], b);
});
result.insert(result.end(), tokens.begin(), tokens.end());
}
if (result.size() > stream.size()) throw std::runtime_error("packing regressed");
return result;
}
const std::vector<int64_t>& bins_;
int width_;
int64_t spatial_size_;
const std::vector<uint64_t>& support_;
const std::vector<std::vector<std::pair<int64_t, int64_t>>>& patterns_;
std::vector<uint64_t> keys_, byte_masks_;
std::vector<int> anchors_, spans_, counts_;
std::vector<Cover> relative_;
std::vector<std::vector<Requirement>> requirements_;
std::vector<std::vector<int64_t>> temporal_by_root_;
std::vector<TrieNode> trie_;
std::array<std::vector<int32_t>, 8> trie_roots_;
int max_cells_ = 1;
std::unordered_map<uint64_t, int64_t> lookup_;
};
} // namespace ac2pack
|