docs: def dtable(self, query):
          """Compute a distance table for a query vector.
          The distances are computed by comparing each sub-vector of the query
          to the codewords for each sub-subspace.
          `dtable[m][ks]` contains the squared Euclidean distance between
          the `m`-th sub-vector of the query and the `ks`-th codeword
          for the `m`-th sub-space (`self.codewords[m][ks]`).
  
          Args:
              query (np.ndarray): Input vector with shape=(D, ) and dtype=np.float32
  
          Returns:
              nanopq.DistanceTable:
                  Distance table. which contains
                  dtable with shape=(M, Ks) and dtype=np.float32
  
          """
          assert query.dtype == np.float32
          assert query.ndim == 1, "input must be a single vector"
          D, = query.shape
          assert D == self.Ds * self.M, "input dimension must be Ds * M"
  
          # dtable[m] : distance between m-th subvec and m-th codewords (m-th subspace)
          # dtable[m][ks] : distance between m-th subvec and ks-th codeword of m-th codewords
          dtable = np.empty((self.M, self.Ks), dtype=np.float32)
          for m in range(self.M):
              query_sub = query[m * self.Ds : (m+1) * self.Ds]
              dtable[m, :] = np.linalg.norm(self.codewords[m] - query_sub, axis=1) ** 2
  
          return DistanceTable(dtable)