Skip to content

Commit 5c59d8e

Browse files
Test that an infinite coordinate does not overflow the chain buffer
An infinite coordinate puts both infinity and NaN in the distance matrix, so the chain can keep extending without finding a mutual pair. Walking past the end of its buffer raised instead of reporting the merges it could not make.
1 parent e6c3d4d commit 5c59d8e

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

test/scholar/cluster/hierarchical_test.exs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,34 @@ defmodule Scholar.Cluster.HierarchicalTest do
401401
assert Nx.to_number(model.sizes[-1]) == 0
402402
end
403403

404+
test "an infinite coordinate does not run the chain past the end of its buffer" do
405+
# An infinite coordinate puts both :infinity and :nan in the distance matrix, since
406+
# subtracting infinities gives NaN. The chain can then keep extending without ever
407+
# finding a mutual pair, and walking past the end of its own buffer raises instead
408+
# of reporting the merges it could not make.
409+
x = Nx.tensor([[0.0, 0.0], [1.0, 1.0], [2.0, 2.0], [:infinity, 0.0]])
410+
411+
model = Hierarchical.fit(x, linkage: :complete)
412+
413+
assert model.num_points == 4
414+
assert Nx.shape(model.clades) == {3, 2}
415+
416+
# Whatever it did merge is still a well formed tree: no clade merged twice, and no
417+
# row naming a clade that is not born yet.
418+
made =
419+
Nx.to_flat_list(model.clades)
420+
|> Enum.chunk_every(2)
421+
|> Enum.zip(Nx.to_flat_list(model.sizes))
422+
|> Enum.reject(fn {_pair, size} -> size == 0 end)
423+
424+
children = Enum.flat_map(made, fn {pair, _size} -> pair end)
425+
assert children == Enum.uniq(children)
426+
427+
assert Enum.all?(Enum.with_index(made), fn {{[a, b], _size}, k} ->
428+
a < model.num_points + k and b < model.num_points + k
429+
end)
430+
end
431+
404432
test "a NaN coordinate still makes every merge" do
405433
# NaN alone does not stall the loop: argmin keeps picking a mutual pair, so every
406434
# merge is made. The dissimilarities really are NaN here, since the distances are,

0 commit comments

Comments
 (0)