Source code for stonesoup.metricgenerator.uncertaintymetric

# -*- coding: utf-8 -*-
from abc import abstractmethod

import numpy as np

from .base import MetricGenerator
from ..types.state import State, StateMutableSequence
from ..types.metric import SingleTimeMetric, TimeRangeMetric
from ..types.time import TimeRange


class _CovarianceNormsMetric(MetricGenerator):
    _type = None

    def compute_metric(self, manager, **kwargs):
        """Computes the metric using the data in the metric manager

        Parameters
        ----------
        manager : :class:`~.MetricManager`
            Contains the data to be used to create the metric

        Returns
        -------
        metric : list :class:`~.Metric`
            Containing the metric information. The value of the metric is a
            list of the metric at each timestamp

        """

        return self.compute_over_time(self.extract_states(manager.tracks))

    @staticmethod
    def extract_states(object_with_states):
        """
        Extracts a list of states from a list of (or single) objects
        containing states. This method is defined to handle :class:`~.StateMutableSequence`
        and :class:`~.State` types.

        Parameters
        ----------
        object_with_states: object containing a list of states
            Method of state extraction depends on the type of the object

        Returns
        -------
        : list of :class:`~.State`
        """

        state_list = StateMutableSequence()
        for element in list(object_with_states):
            if isinstance(element, StateMutableSequence):
                state_list.extend(element.states)
            elif isinstance(element, State):
                state_list.append(element)
            else:
                raise ValueError(
                    "{!r} has no state extraction method".format(element))

        return state_list

    def compute_over_time(self, track_states):
        """Compute the metric using the data in the metric manager

        Parameters
        ----------
        track_states : list of :class:`~.State`
            List of states created by a filter

        Returns
        ----------
        metric : TimeRangeMetric
            Covering the duration that states exist for in the parameters.
            Metric.value contains a list of the summarised covariance matrix norms
            at each timestamp

        """

        # Make a sorted list of all the unique timestamps used
        timestamps = sorted({state.timestamp for state in track_states})

        covnorms = []

        for timestamp in timestamps:
            track_points = [state for state in track_states if state.timestamp == timestamp]
            covnorms.append(self.compute_covariancenorms(track_points))

        return TimeRangeMetric(
            title=f'{self._type} of Covariance Norms Metric',
            value=covnorms,
            time_range=TimeRange(min(timestamps), max(timestamps)),
            generator=self)

    @abstractmethod
    def compute_covariancenorms(self, track_states):
        raise NotImplementedError

    @staticmethod
    def _get_unique_timestamp(track_states):
        timestamps = {state.timestamp for state in track_states}
        if len(timestamps) > 1:
            raise ValueError(
                'All states must be from the same time to compute total uncertainty')
        return timestamps.pop()


[docs]class SumofCovarianceNormsMetric(_CovarianceNormsMetric): """ Computes the sum of the covariance matrix norms of each state at a time step. The matrix norm calculated is the Frobenius norm. The metric generator will return this value at each time step in the track(s) as a measure of the uncertainty. """ _type = "Sum"
[docs] def compute_covariancenorms(self, track_states): """ Computes the sum of covariance norms metric for a single time step. Parameters ---------- track_states: list of :class:`~.State` List of states created by a filter Returns ------- metric: SingleTimeMetric The sum of covariance matrix norms metric at a single time step """ timestamp = self._get_unique_timestamp(track_states) covnorms_sum = sum(np.linalg.norm(state.covar) for state in track_states) return SingleTimeMetric(title='Covariance Matrix Norm Sum', value=covnorms_sum, timestamp=timestamp, generator=self)
[docs]class MeanofCovarianceNormsMetric(_CovarianceNormsMetric): _type = "Mean"
[docs] def compute_covariancenorms(self, track_states): """ Computes the mean of covariance norms metric for a single time step. Parameters ---------- track_states: list of :class:`~.State` List of states created by a filter Returns ------- metric: SingleTimeMetric The mean of covariance matrix norms metric at a single time step """ timestamp = self._get_unique_timestamp(track_states) covnorms_sum = sum(np.linalg.norm(state.covar) for state in track_states) covnorms_mean = covnorms_sum / len(track_states) return SingleTimeMetric(title='Covariance Matrix Norm Mean', value=covnorms_mean, timestamp=timestamp, generator=self)