CoreSGClusterer Workflow
========================
``CoreSGClusterer`` gives the same reuse behavior through an estimator-shaped
API:
.. code-block:: python
from core_sg import CoreSGClusterer
clusterer = CoreSGClusterer(k_max=30)
for k in [25, 20, 15, 10]:
clusterer.fit(X, k=k)
labels = clusterer.labels_
.. raw:: html
CoreSGClusterer lifecycle
User calls fit(X, k=25)
↓
Estimator creates core_sg_ and builds support at k_max=30
↓
Estimator exposes attributes for k=25
↓
User calls fit(X, k=20)
↓
Estimator reuses the existing core_sg_ object
↓
Estimator exposes updated attributes for k=20
The rebuild decision is based on whether core_sg_ exists, not on whether k equals k_max.
The first call builds ``core_sg_``. Later calls reuse the same object and only
extract a new hierarchy.
``labels_`` updates after each call and corresponds to the most recent ``k``.
The internal reusable object remains available through ``clusterer.core_sg_``
or ``clusterer.get_fitted_core_sg()`` for advanced inspection.
``fit_predict(...)`` is available:
.. code-block:: python
labels = clusterer.fit_predict(X, k=10)
``predict(...)`` is not implemented because unseen-sample assignment semantics
are not part of the current Core-SG API.