function assignClusterId(samples, centroids, fillEmpty = true) {
  return tf.tidy(() => {
    // perform outer operations by expanding dimensions
    const expandedVectors = tf.expandDims(samples, 0);
    const expandedCentroids = tf.expandDims(centroids, 1);
    const distances = tf.sum(
      tf.square(tf.sub(expandedVectors, expandedCentroids)),
      2
    );
    if (fillEmpty) {
      return fillEmptyClusters(distances);
    }
    const mins = tf.argMin(distances, 0);
    return mins.toInt();
  });
}
give each data instance a cluster assignment, based on which cluster centroid is nearest to it
@param {Tensor2D} samples - data points being clustered, shape = [nInstances, nDims]
@param {Tensor2D} centroids - positions of cluster centers, shape = [nClusters, nDims]
@param {Boolean} fillEmpty - whether to enforce all clusters to be non-empty
@returns {Tensor1D} indices of the nearest centroid to each data instance, shape = [nInscances]