25 std::ifstream f(
path, std::ios::binary);
27 std::cerr <<
"[ControllerLUT] Failed to open: " <<
path << std::endl;
32 if (!f.read(
reinterpret_cast<char*
>(magic), 4) || std::memcmp(magic,
MAGIC, 4) != 0) {
33 std::cerr <<
"[ControllerLUT] Invalid magic in " <<
path << std::endl;
37 uint8_t version, num_axes, num_outputs, reserved;
38 if (!f.read(
reinterpret_cast<char*
>(&version), 1) || version != VERSION) {
39 std::cerr <<
"[ControllerLUT] Unsupported version " << (int)version << std::endl;
42 if (!f.read(
reinterpret_cast<char*
>(&num_axes), 1) || num_axes > MAX_AXES) {
43 std::cerr <<
"[ControllerLUT] Invalid num_axes " << (int)num_axes << std::endl;
46 if (!f.read(
reinterpret_cast<char*
>(&num_outputs), 1) || num_outputs > MAX_OUTPUTS) {
47 std::cerr <<
"[ControllerLUT] Invalid num_outputs " << (int)num_outputs << std::endl;
50 if (!f.read(
reinterpret_cast<char*
>(&reserved), 1))
53 for (uint8_t
a = 0;
a < num_axes; ++
a) {
56 if (!f.read(
reinterpret_cast<char*
>(&name_len), 1))
58 ax.name.resize(std::min(
static_cast<size_t>(name_len), MAX_NAME_LEN));
59 if (!f.read(&ax.name[0], ax.name.size()))
61 if (name_len > MAX_NAME_LEN)
62 f.ignore(name_len - MAX_NAME_LEN);
65 if (!f.read(
reinterpret_cast<char*
>(&grid_len), 4))
67 ax.grid.resize(grid_len);
68 if (!f.read(
reinterpret_cast<char*
>(ax.grid.data()), grid_len *
sizeof(
double)))
71 axes_.push_back(std::move(ax));
74 for (uint8_t
o = 0;
o < num_outputs; ++
o) {
77 if (!f.read(
reinterpret_cast<char*
>(&name_len), 1))
79 out.name.resize(std::min(
static_cast<size_t>(name_len), MAX_NAME_LEN));
80 if (!f.read(&out.name[0], out.name.size()))
82 if (name_len > MAX_NAME_LEN)
83 f.ignore(name_len - MAX_NAME_LEN);
85 out.shape.resize(
axes_.size());
86 if (!f.read(
reinterpret_cast<char*
>(out.shape.data()),
axes_.size() *
sizeof(uint32_t)))
90 for (uint32_t s : out.shape)
92 out.data.resize(total);
93 if (!f.read(
reinterpret_cast<char*
>(out.data.data()), total *
sizeof(
double)))
99 std::cout <<
"[ControllerLUT] Loaded " <<
path <<
" (" <<
axes_.size() <<
" axes, "
100 <<
outputs_.size() <<
" outputs)" << std::endl;
105 std::map<std::string, double>& out)
const {
110 const size_t n_axes =
axes_.size();
118 std::vector<AxisInfo> infos;
119 infos.reserve(n_axes);
121 for (
const auto& ax :
axes_) {
122 auto it = point.find(ax.name);
123 if (it == point.end()) {
124 std::cerr <<
"[ControllerLUT] Missing axis '" << ax.name <<
"' in point" << std::endl;
127 double x = it->second;
128 const auto& grid = ax.grid;
132 size_t hi = std::lower_bound(grid.begin(), grid.end(), x) - grid.begin();
135 if (hi >= grid.size())
136 hi = grid.size() - 1;
139 double x0 = grid[lo];
140 double x1 = grid[hi];
141 double t = (x1 == x0) ? 0.0 : (x - x0) / (x1 - x0);
142 t = std::clamp(t, 0.0, 1.0);
143 infos.push_back({lo, hi, 1.0 - t, t});
146 for (
const auto& output :
outputs_) {
147 std::vector<size_t> strides(n_axes);
148 strides[n_axes - 1] = 1;
149 for (
int i =
static_cast<int>(n_axes) - 2; i >= 0; --i)
150 strides[i] = strides[i + 1] * output.shape[i + 1];
153 const size_t n_corners = 1ULL << n_axes;
154 for (
size_t corner = 0; corner < n_corners; ++corner) {
157 for (
size_t i = 0; i < n_axes; ++i) {
158 size_t idx = (corner >> i) & 1 ? infos[i].hi : infos[i].lo;
159 double wi = (corner >> i) & 1 ? infos[i].w1 : infos[i].w0;
161 flat_idx += idx * strides[i];
163 if (w >= 1e-10 && flat_idx < output.data.size()) {
164 double v = output.data[flat_idx];
165 if (std::isfinite(v))
169 out[output.name] =
result;
static const uint8_t MAGIC[MAGIC_SIZE]