Skip to content

Expose OPTICS's reachability graph - #366

Merged
josevalim merged 2 commits into
elixir-nx:mainfrom
RicardoSantos-99:add-optics-reachability-fields
Aug 30, 2026
Merged

Expose OPTICS's reachability graph#366
josevalim merged 2 commits into
elixir-nx:mainfrom
RicardoSantos-99:add-optics-reachability-fields

Conversation

@RicardoSantos-99

Copy link
Copy Markdown
Contributor

Scholar.Cluster.OPTICS.fit/2 computes the full reachability graph but only keeps the labels. compute_optics_graph builds core_distances, reachability, predecessor and ordering, then fit_p feeds them into cluster_optics_dbscan and discards them at the end of the function.

That graph is not an internal detail. ordering against reachability is the reachability plot, the standard way OPTICS results are read and the way clusters are told apart from noise visually, and it is what predecessor and core_distances support (tracing how a point was reached, and at what radius it became a core point). None of it survives past fit/2 today, so nothing built on Scholar can draw one.

This adds :reachability, :core_distances, :ordering and :predecessor to the struct, populated the same way :labels already is.

compute_optics_graph already builds reachability, core_distances,
ordering and predecessor, but fit/2 only kept labels and discarded the
rest at the end of the function. These are what a reachability plot,
the standard way to read an OPTICS run, is drawn from.

core_distances is flattened before being returned: it carries a
trailing size-1 axis from the neighbor search it is sliced out of,
which the internal code accommodates through broadcasting but which
has no reason to leak into the public field.

No test file existed for this module, so one was added: doctest plus
values checked against scikit-learn 1.6.1 on the moduledoc's own data.
@RicardoSantos-99

Copy link
Copy Markdown
Contributor Author

Would it make sense to cut a new release soon? maybe v0.5.0

@josevalim

Copy link
Copy Markdown
Contributor

We can do a new release soon.

For this PR, can we improve the tests? They are converting too many values and asserting on shapes. Ideally we want to assert on values and rely Nx.all_close if possible.

@josevalim

Copy link
Copy Markdown
Contributor

Sorry, assert_all_close!

@RicardoSantos-99
RicardoSantos-99 force-pushed the add-optics-reachability-fields branch from e7ba261 to 0db755b Compare August 28, 2026 18:33
@RicardoSantos-99

Copy link
Copy Markdown
Contributor Author

We can do a new release soon.

For this PR, can we improve the tests? They are converting too many values and asserting on shapes. Ideally we want to assert on values and rely Nx.all_close if possible.

Done

RicardoSantos-99 added a commit to RicardoSantos-99/verdict that referenced this pull request Aug 29, 2026
OPTICS does not hand back clusters so much as an ordering with a distance
attached to every point. The reachability plot is how that ordering is
read: a valley is a cluster, the walls either side say how separated it
is, and one picture replaces a run at several cut-offs.

Both the distances and the labels are read through the model's ordering.
They are stored in the order the points were given, and only mean
something in the order OPTICS reached them, which is what puts each
point beside the one it was reached from. Verified against scikit-learn
1.6.1, whose reachability_[ordering_] is the same arrangement and whose
raw arrays Scholar matches value for value.

A point OPTICS could not reach carries an infinite distance, which no
axis can hold and which Jason encodes as the string "infinity" if it is
left alone. Those are drawn as full-height dashed rules rather than
bars, so the wall stays visible without a number being invented for it.
The first point in the ordering is always one of them.

The cut-off the clusters were extracted at is drawn as a reference, and
takes a value of its own, which is how the next eps to try gets chosen
without fitting again. It is left out when the model's own eps is
infinite, since that has no position on the axis either.

Needs Scholar's OPTICS to expose reachability, ordering and labels,
which is elixir-nx/scholar#366.
@josevalim
josevalim merged commit a5afae5 into elixir-nx:main Aug 30, 2026
2 checks passed
@josevalim

Copy link
Copy Markdown
Contributor

💚 💙 💜 💛 ❤️

@RicardoSantos-99
RicardoSantos-99 deleted the add-optics-reachability-fields branch August 30, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants