void vector_of_kll_sketches::update()

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));
  }
}