From 8bb9a18e8f33fe186ff2418b4dbe57570a86b672 Mon Sep 17 00:00:00 2001 From: Caroline Malin-Mayor Date: Tue, 5 Nov 2024 14:40:09 -0500 Subject: [PATCH 1/4] Unify appear and disappear cost functionality --- motile/costs/appear.py | 6 ++++-- motile/costs/disappear.py | 29 ++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/motile/costs/appear.py b/motile/costs/appear.py index 80985e7..e999c3e 100644 --- a/motile/costs/appear.py +++ b/motile/costs/appear.py @@ -17,18 +17,20 @@ class Appear(Cost): Args: weight: - The weight to apply to the cost of each starting track. + The weight to apply to the cost attribute of each starting track. + Defaults to 1. attribute: The name of the attribute to use to look up cost. Default is ``None``, which means that a constant cost is used. constant: - A constant cost for each node that starts a track. + A constant cost for each node that starts a track. Defaults to 0. ignore_attribute: The name of an optional node attribute that, if it is set and evaluates to ``True``, will not set the appear cost for that node. + Defaults to None """ def __init__( diff --git a/motile/costs/disappear.py b/motile/costs/disappear.py index 89f2bdb..b8a20b3 100644 --- a/motile/costs/disappear.py +++ b/motile/costs/disappear.py @@ -16,17 +16,32 @@ class Disappear(Cost): This is cost is not applied to nodes in the last frame of the graph. Args: - constant (float): - A constant cost for each node that ends a track. + weight: + The weight to apply to the cost of each ending track. Defaults to 1. + + attribute: + The name of the attribute to use to look up cost. Default is + ``None``, which means that a constant cost is used. + + constant: + A constant cost for each node that starts a track. Defaults to 0. ignore_attribute: The name of an optional node attribute that, if it is set and - evaluates to ``True``, will not set the disappear cost for that - node. + evaluates to ``True``, will not set the disappear cost for that node. + Defaults to None. """ - def __init__(self, constant: float, ignore_attribute: str | None = None) -> None: + def __init__( + self, + weight: float = 1, + attribute: str | None = None, + constant: float = 0, + ignore_attribute: str | None = None, + ): + self.weight = Weight(weight) self.constant = Weight(constant) + self.attribute = attribute self.ignore_attribute = ignore_attribute def apply(self, solver: Solver) -> None: @@ -39,4 +54,8 @@ def apply(self, solver: Solver) -> None: continue if G.nodes[node][G.frame_attribute] == G.get_frames()[1] - 1: continue + if self.attribute is not None: + solver.add_variable_cost( + index, G.nodes[node][self.attribute], self.weight + ) solver.add_variable_cost(index, 1.0, self.constant) From c06b8ac621453446f6e1333e7427264524b4b95d Mon Sep 17 00:00:00 2001 From: Caroline Malin-Mayor Date: Tue, 5 Nov 2024 14:44:30 -0500 Subject: [PATCH 2/4] Make edge selection attribute optional --- motile/costs/edge_selection.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/motile/costs/edge_selection.py b/motile/costs/edge_selection.py index 68365b6..3dea96d 100644 --- a/motile/costs/edge_selection.py +++ b/motile/costs/edge_selection.py @@ -15,19 +15,19 @@ class EdgeSelection(Cost): Args: weight: - The weight to apply to the cost given by the ``cost`` attribute of - each edge. + The weight to apply to the cost given by the provided attribute of + each edge. Default is ``1.0``. attribute: The name of the edge attribute to use to look up cost. Default is - ``'cost'``. + None, which means only a constant cost is used. constant: A constant cost for each selected edge. Default is ``0.0``. """ def __init__( - self, weight: float, attribute: str = "cost", constant: float = 0.0 + self, weight: float = 1, attribute: str | None = None, constant: float = 0.0 ) -> None: self.weight = Weight(weight) self.constant = Weight(constant) @@ -37,7 +37,8 @@ def apply(self, solver: Solver) -> None: edge_variables = solver.get_variables(EdgeSelected) for edge, index in edge_variables.items(): - solver.add_variable_cost( - index, solver.graph.edges[edge][self.attribute], self.weight - ) + if self.attribute is not None: + solver.add_variable_cost( + index, solver.graph.edges[edge][self.attribute], self.weight + ) solver.add_variable_cost(index, 1.0, self.constant) From 3681816a579fb55f439e02ebf78f473a298327fd Mon Sep 17 00:00:00 2001 From: Caroline Malin-Mayor Date: Tue, 5 Nov 2024 14:45:44 -0500 Subject: [PATCH 3/4] Make node selection attribute optional --- motile/costs/node_selection.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/motile/costs/node_selection.py b/motile/costs/node_selection.py index fb17bd0..5e6b3b5 100644 --- a/motile/costs/node_selection.py +++ b/motile/costs/node_selection.py @@ -15,19 +15,19 @@ class NodeSelection(Cost): Args: weight: - The weight to apply to the cost given by the ``cost`` attribute of - each node. + The weight to apply to the cost given by the provided attribute of + each node. Default is ``1.0`` attribute: - The name of the node attribute to use to look up cost. Default is - ``'cost'``. + The name of the node attribute to use to look up cost, or None if a constant + cost is desired. Default is ``None``. constant: A constant cost for each selected node. Default is ``0.0``. """ def __init__( - self, weight: float, attribute: str = "cost", constant: float = 0.0 + self, weight: float = 1, attribute: str | None = None, constant: float = 0.0 ) -> None: self.weight = Weight(weight) self.constant = Weight(constant) @@ -37,7 +37,8 @@ def apply(self, solver: Solver) -> None: node_variables = solver.get_variables(NodeSelected) for node, index in node_variables.items(): - solver.add_variable_cost( - index, solver.graph.nodes[node][self.attribute], self.weight - ) + if self.attribute is not None: + solver.add_variable_cost( + index, solver.graph.nodes[node][self.attribute], self.weight + ) solver.add_variable_cost(index, 1.0, self.constant) From 4ce3048a476b4b345b1dc60103fd4c52fd7ba2e0 Mon Sep 17 00:00:00 2001 From: Caroline Malin-Mayor Date: Tue, 5 Nov 2024 14:48:52 -0500 Subject: [PATCH 4/4] Update documentation of split cost --- motile/costs/split.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/motile/costs/split.py b/motile/costs/split.py index 1f97627..7608cfa 100644 --- a/motile/costs/split.py +++ b/motile/costs/split.py @@ -15,7 +15,7 @@ class Split(Cost): Args: weight: - The weight to apply to the cost of each split. + The weight to apply to the cost of each split. Default is ``1``. attribute: The name of the attribute to use to look up the cost. Default is @@ -23,7 +23,7 @@ class Split(Cost): constant: A constant cost for each node that has more than one selected - child. + child. Default is ``0``. """ def __init__(