Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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
70 changes: 69 additions & 1 deletion deeptrack/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def merge_features(
from deeptrack.backend.core import DeepTrackNode
from deeptrack.backend.units import ConversionTable, create_context
from deeptrack.image import Image
from deeptrack.properties import PropertyDict
from deeptrack.properties import PropertyDict, SequentialProperty
from deeptrack.sources import SourceItem
from deeptrack.types import ArrayLike, PropertyLike

Expand Down Expand Up @@ -493,6 +493,74 @@ def __call__(

resolve = __call__

def to_sequential(
feature: Feature,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be self

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corrected.

**kwargs
) -> Feature:
"""Converts a feature to be resolved as a sequence.

Should be called on individual features, not combinations of features. All
keyword arguments will be treated as sequential properties and will be
passed to the parent feature.

If a property from the keyword argument already exists on the feature, the
existing property will be used to initialize the passed property (that is,
it will be used for the first timestep).

Parameters
----------
feature: Feature
Feature to make sequential.
kwargs
Keyword arguments to pass on as sequential properties of `feature`.

Returns
-------
Feature
The input feature evolved as a sequence

"""

for property_name in kwargs.keys():

if property_name in feature.properties:
# Insert property with initialized value
feature.properties[property_name] = SequentialProperty(
feature.properties[property_name], **feature.properties
)
else:
# insert empty property
feature.properties[property_name] = SequentialProperty()

feature.properties.add_dependency(feature.properties[property_name])
feature.properties[property_name].add_child(feature.properties)

for property_name, sampling_rule in kwargs.items():

prop = feature.properties[property_name]

all_kwargs = dict(
previous_value=prop.previous_value,
previous_values=prop.previous_values,
sequence_length=prop.sequence_length,
sequence_step=prop.sequence_step,
)

for key, val in feature.properties.items():
if key == property_name:
continue

if isinstance(val, SequentialProperty):
all_kwargs[key] = val
all_kwargs["previous_" + key] = val.previous_values
else:
all_kwargs[key] = val
if not prop.initialization:
prop.initialization = prop.create_action(sampling_rule, **{k:all_kwargs[k] for k in all_kwargs if k != "previous_value"})

prop.current = prop.create_action(sampling_rule, **all_kwargs)

return feature

def store_properties(
self: Feature,
Expand Down
59 changes: 57 additions & 2 deletions deeptrack/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
import numpy as np

from .utils import get_kwarg_names
from .backend.core import DeepTrackNode
from deeptrack.backend.core import DeepTrackNode


class Property(DeepTrackNode):
Expand Down Expand Up @@ -530,6 +530,7 @@ class SequentialProperty(Property):
def __init__(
self,
initialization: Optional[Any] = None,
current_value: Optional[Any] = None,
**kwargs: Dict[str, 'Property'],
):
"""Create a SequentialProperty with optional initialization.
Expand Down Expand Up @@ -586,7 +587,10 @@ def __init__(
self.initialization = None

# 6) Define a default current function for steps >= 1.
self.current = lambda _ID=(): None
if current_value is not None:
self.current = self.create_action(current_value, **kwargs)
else:
self.current = lambda _ID=(): None

# 7) Override the default action with our custom logic.
self.action = self._action_override
Expand Down Expand Up @@ -682,3 +686,54 @@ def __call__(self, _ID: Tuple[int, ...] = ()) -> Any:
"""

return super().__call__(_ID=_ID)

def set_sequence_length(
self,
value: Any,
_ID: Tuple[int, ...] = ()
) -> None:
"""Sets the `sequence_length` attribute of a sequence to be resolved.

Supports dependencies if `value` is a `Property`.

Parameters
----------
value : Any
The value to store in `sequence_length`.
_ID : Tuple[int, ...], optional
A unique identifier that allows the property to keep separate
histories for different parallel evaluations.

"""

if isinstance(value, Property):
self.sequence_length = Property(lambda _ID: value(_ID))
self.sequence_length.add_dependency(value)
else:
self.sequence_length = Property(value, _ID=_ID)

def set_current_step(
self,
value: Any,
_ID: Tuple[int, ...] = ()
) -> None:
"""Sets the `current_index` attribute of a sequence to be resolved.

Supports dependencies if `value` is a `Property`.

Parameters
----------
value : Any
The value to store in `current_step`.

_ID : Tuple[int, ...], optional
A unique identifier that allows the property to keep separate
histories for different parallel evaluations.

"""

if isinstance(value, Property): # For dependencies.
self.sequence_step = Property(lambda _ID: value(_ID))
self.sequence_step.add_dependency(value)
else:
self.sequence_step = Property(value, _ID=_ID)
2 changes: 1 addition & 1 deletion deeptrack/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def get(self, input_list, sequence_length=None, **kwargs):
return outputs


def Sequential(feature: Feature, **kwargs):
def Sequential(feature: Feature, **kwargs): #TBE, Replaced by Feature.to_sequential()
"""Converts a feature to be resolved as a sequence.

Should be called on individual features, not combinations of features. All
Expand Down