Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions trackpy/linking/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ def in_track(self):
def track(self):
"""Returns the track that this :class:`Point` is in. May be `None` """
return self._track

def __hash__(self):
"""Returns a deterministic value so that set() order is more stable."""
return self.uuid


class TrackUnstored:
Expand Down
1 change: 1 addition & 0 deletions trackpy/tests/test_find_link.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
class FindLinkTests(SubnetNeededTests):
def setUp(self):
super().setUp()
self.coordinates_exact = False # b/c we roundtrip to images
self.linker_opts['separation'] = 10
self.linker_opts['diameter'] = 15
self.linker_opts['preprocess'] = False
Expand Down
53 changes: 53 additions & 0 deletions trackpy/tests/test_linking.py
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,43 @@ def test_penalty(self):
pandas_sort(actual, ['x'], inplace=True)
assert_equal(actual['particle'].values.astype(int),
case2['particle'].values.astype(int))

def test_degeneracy_forward(self):
"""Check that a trivial degenerate subnet is resolved stably."""
if not getattr(self, 'coordinates_exact', True):
return # Test will not be meaningful
result_counts = {0: 0, 1: 0}
for i in range(100):
# degen_df = pd.DataFrame({
# 'y': [-1, 1, 0],
# 'x': [-1, 1, 0],
# 'frame': [ 0, 0, 1]
# })
degen_df = pd.DataFrame({
'y': [0, -1, 1],
'x': [0, -1, 1],
'frame': [0, 1, 1]
})
out = self.link(degen_df, search_range=1.8, t_column="frame")
result_counts[out.particle.iloc[-1]] += 1
# There are two degenerate forward candidates for the last frame.
assert any((c == 100 for c in result_counts.values())) # Stable

def test_degeneracy_source(self):
"""Check that a trivial degenerate subnet is resolved stably."""
if not getattr(self, 'coordinates_exact', True):
return # Test will not be meaningful
result_counts = {0: 0, 1: 0}
for i in range(100):
degen_df = pd.DataFrame({
'y': [-1, 1, 0],
'x': [-1, 1, 0],
'frame': [ 0, 0, 1]
})
out = self.link(degen_df, search_range=1.8, t_column="frame")
result_counts[out.particle.iloc[-1]] += 1
# There are two degenerate source candidates for the last frame.
assert any((c == 100 for c in result_counts.values())) # Stable

def test_memory(self):
"""A unit-stepping trajectory and a random walk are observed
Expand Down Expand Up @@ -565,6 +602,22 @@ def test_memory_on_one_gap(self):
actual = self.link(f1, 5, memory=1)
assert_traj_equal(actual, expected)

def test_memory_degeneracy(self):
"""Check that with memory, degeneracies are resolved stably."""
if not getattr(self, 'coordinates_exact', True):
return # Test will not be meaningful
result_counts = {0: 0, 1: 0}
for i in range(100):
mem_df = pd.DataFrame({
'y': [-1, 1, 100, 0],
'x': [-1, 1, 100, 0],
'frame': [ 0, 0, 1, 2]
})
out = self.link(mem_df, search_range=1.8, memory=1, t_column="frame")
result_counts[out.particle.iloc[-1]] += 1
# With memory > 0, there are two degenerate candidates for the last frame.
assert any((c == 100 for c in result_counts.values())) # Stable

def test_pathological_tracking(self):
level_count = 5
p_count = 16
Expand Down
Loading