Skip to content

Commit

Permalink
Merge pull request #200 from dstl/Multi_Deleter
Browse files Browse the repository at this point in the history
Added multi-deleter methods
  • Loading branch information
sdhiscocks committed May 4, 2020
2 parents 35f4d3c + 569967b commit 7f6b95c
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/source/stonesoup.deleter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,9 @@ Time Based
.. automodule:: stonesoup.deleter.time
:show-inheritance:
:inherited-members:

Multi
-----
.. automodule:: stonesoup.deleter.multi
:show-inheritance:
:inherited-members:
45 changes: 45 additions & 0 deletions stonesoup/deleter/multi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""Contains deleters which use a composite of deleters to decide whether a track is to be deleted
"""

from ..base import Property
from .base import Deleter


class CompositeDeleter(Deleter):
""" Track deleter composed of multiple deleters.
If :attr:`intersect` is True, deletes tracks if they satisfy the deletion conditions of each
deleter listed in :attr:`deleters`. Otherwise deletes tracks if they satisfy the conditions of
at least one deleter listed.
"""

deleters = Property([Deleter], doc="List of deleters to be applied to the track")
intersect = Property(
bool, default=True,
doc="Boolean that determines whether the composite deleter will intersect or unify "
"deletion results. Default is `True`, applying an intersection.")

def check_for_deletion(self, track, **kwargs):
"""Check if a given track should be deleted.
Parameters
----------
track : :class:`stonesoup.types.Track`
A track object to be checked for deletion.
Returns
-------
: :class:`bool`
`True` if track should be deleted, `False` otherwise.
"""
if self.intersect:
for deleter in self.deleters:
if not deleter.check_for_deletion(track, **kwargs):
return False
return True
else:
for deleter in self.deleters:
if deleter.check_for_deletion(track, **kwargs):
return True
return False
109 changes: 109 additions & 0 deletions stonesoup/deleter/tests/test_multi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
import datetime

import numpy as np
import pytest

from ..error import CovarianceBasedDeleter
from ..multi import CompositeDeleter
from ..time import UpdateTimeDeleter
from ...types.detection import Detection
from ...types.hypothesis import SingleHypothesis
from ...types.state import GaussianState
from ...types.track import Track
from ...types.update import GaussianStateUpdate


@pytest.fixture(params=[True, False])
def intersect(request):
return request.param


def test_multi_deleter_single(intersect):
"""Test multi deleter classes with a single deleter"""

# Create covariance based deleter
timestamp = datetime.datetime.now()
state = GaussianState(
np.array([[0], [0]]),
np.array([[100, 0], [0, 1]]), timestamp)
track = Track()
track.append(state)
tracks = {track}
state = GaussianState(
np.array([[0], [0]]),
np.array([[1, 0], [0, 1]]), timestamp)
track = Track()
track.append(state)
tracks.add(track)
cover_deletion_thresh = 100
deleter = CovarianceBasedDeleter(cover_deletion_thresh)

# Test intersect deleter
multi_deleter = CompositeDeleter([deleter], intersect)
deleted_tracks = multi_deleter.delete_tracks(tracks)
tracks -= deleted_tracks

assert (len(tracks) == 1)
assert (len(deleted_tracks) == 1)


def test_multi_deleter_multiple(intersect):
"""Test multi deleter classes with multiple deleters"""

cover_deletion_thresh = 99
deleter = CovarianceBasedDeleter(cover_deletion_thresh)
deleter2 = UpdateTimeDeleter(datetime.timedelta(minutes=10))
multi_deleter = CompositeDeleter([deleter, deleter2], intersect)

# Create track that is not deleted by either deleter
track = Track([
GaussianState(
np.array([[0]]),
np.array([[10]]),
timestamp=datetime.datetime(2018, 1, 1, 10)),
GaussianStateUpdate(
[[0]],
np.array([[10]]),
SingleHypothesis(None, Detection([[0]])),
timestamp=datetime.datetime(2018, 1, 1, 14))
])
tracks = {track}
deleted_tracks = multi_deleter.delete_tracks(tracks)
tracks -= deleted_tracks

assert (len(tracks) == 1)
assert (len(deleted_tracks) == 0)

# Create track that is deleted by cbd but not time deleter
track = Track([
GaussianState(
np.array([[0]]),
np.array([[100]]),
timestamp=datetime.datetime(2018, 1, 1, 10)),
GaussianStateUpdate(
[[0]],
np.array([[100]]),
SingleHypothesis(None, Detection([[0]])),
timestamp=datetime.datetime(2018, 1, 1, 14))
])
tracks = {track}

deleted_tracks = multi_deleter.delete_tracks(tracks)
tracks -= deleted_tracks

if intersect:
assert len(tracks) == 1
assert len(deleted_tracks) == 0
else:
assert len(tracks) == 0
assert len(deleted_tracks) == 1

# Create track that is deleted by both cbd and time deleter
tracks = {track}
new_time = datetime.datetime(2018, 1, 1, 14, 25)
deleted_tracks = multi_deleter.delete_tracks(tracks, timestamp=new_time)
tracks -= deleted_tracks

assert (len(tracks) == 0)
assert (len(deleted_tracks) == 1)

0 comments on commit 7f6b95c

Please sign in to comment.