in src/vector_of_kll.cpp [261:304]
void vector_of_kll_sketches<T, C>::update(nb::ndarray<T>& items, char order) {
size_t ndim = items.ndim();
if (items.shape(ndim-1) != d_) {
throw std::invalid_argument("input data must have rows with " + std::to_string(d_)
+ " elements. Found: " + std::to_string(items.shape(ndim-1)));
}
if (ndim == 1) {
// 1D case: single value to update per sketch
const T* data = items.data();
for (uint32_t i = 0; i < d_; ++i) {
sketches_[i].update(data[i]);
}
}
else if (ndim == 2) {
// 2D case: multiple values to update per sketch
// We could speedthis up by using raw array access and pre-computing an offset for the
// row/column, but if we use the wrong ordering the computation would be incorrect.
// By using a view and dereferencing by (row, column) each time we ensure correct
// processing at the cost of an extra multiply each derference. Using a mismatched
// ordering versus the actual data storage will be potentially slower but will still
// produce correct output.
auto data = items.template view<nb::ndim<2>>();
if (order == 'F' || order == 'f') { // Fortran-style (column-major) order
for (uint32_t j = 0; j < d_; ++j) {
const size_t offset = j * d_;
for (uint32_t i = 0; i < items.shape(0); ++i) {
sketches_[j].update(data(i, j));
}
}
} else { // nb::c_contig or nb::any_contig
for (uint32_t i = 0; i < items.shape(0); ++i) {
const size_t offset = i * items.shape(0);
for (uint32_t j = 0; j < d_; ++j) {
sketches_[j].update(data(i, j));
}
}
}
}
else {
throw std::invalid_argument("Update input must be 2 or fewer dimensions : " + std::to_string(ndim));
}
}