From 510a9d5f4e252484611d42a0f1b1cb65ca44d6fe Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 07:38:02 +0100 Subject: [PATCH 001/105] Update types.py --- deeptrack/types.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/deeptrack/types.py b/deeptrack/types.py index 0f32b00ee..651b5eef8 100644 --- a/deeptrack/types.py +++ b/deeptrack/types.py @@ -1,12 +1,24 @@ -""" Type declarations for internal use +""" Type declarations for internal use. + +This module defines type aliases and utility types to standardize the type +annotations used throughout the codebase. It enhances code readability, +maintainability, and reduces redundancy in type annotations. These types are +particularly useful for properties and array-like structures used within the +library. """ +import numpy as np import typing -import numpy as np +# Property type declaration. -# Property type declaration +# T is a generic type variable defining generic types for reusability. T = typing.TypeVar("T") + +# PropertyLike is a type alias representing a value of type T +# or a callable returning type T. PropertyLike = typing.Union[T, typing.Callable[..., T]] -ArrayLike = typing.Union[typing.Tuple[T], typing.List[T], np.ndarray] +# ArrayLike is a type alias representing any array-like structure. +# It supports tuples, lists, and numpy arrays containing elements of type T. +ArrayLike = typing.Union[typing.Tuple[T], typing.List[T], np.ndarray] \ No newline at end of file From 5bb4f8ec23cca7c322844bbaaa7a49920b700e57 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 07:40:02 +0100 Subject: [PATCH 002/105] Update types.py --- deeptrack/types.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/deeptrack/types.py b/deeptrack/types.py index 651b5eef8..61392a3a8 100644 --- a/deeptrack/types.py +++ b/deeptrack/types.py @@ -10,8 +10,6 @@ import numpy as np import typing -# Property type declaration. - # T is a generic type variable defining generic types for reusability. T = typing.TypeVar("T") From c13d10018243bf03e75dec7957046810a773e049 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 07:45:45 +0100 Subject: [PATCH 003/105] Update math.py --- deeptrack/math.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/deeptrack/math.py b/deeptrack/math.py index 9dcb22e16..210d2db19 100644 --- a/deeptrack/math.py +++ b/deeptrack/math.py @@ -1,11 +1,16 @@ -""" Mathematical oprations and structures +"""Mathematical operations and structures. -Classses --------- +This module provides classes and utilities to perform common mathematical +operations and transformations on images, including clipping, normalization, +blurring, and pooling. These are implemented as subclasses of `Feature` for +seamless integration with the feature-based design of the library. + +Classes +------- Clip - Clip the input within a minimum and a maximum value. + Clip the input values within a specified minimum and maximum range. NormalizeMinMax - Min-max image normalization. + Perform min-max normalization on images. """ from typing import Callable, List From 36e56bff46a34ebe13818118b0117a2ef136c331 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe <46021832+giovannivolpe@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:49:02 +0100 Subject: [PATCH 004/105] Update types.py --- deeptrack/types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/types.py b/deeptrack/types.py index 61392a3a8..389f410d0 100644 --- a/deeptrack/types.py +++ b/deeptrack/types.py @@ -1,4 +1,4 @@ -""" Type declarations for internal use. +"""Type declarations for internal use. This module defines type aliases and utility types to standardize the type annotations used throughout the codebase. It enhances code readability, @@ -19,4 +19,4 @@ # ArrayLike is a type alias representing any array-like structure. # It supports tuples, lists, and numpy arrays containing elements of type T. -ArrayLike = typing.Union[typing.Tuple[T], typing.List[T], np.ndarray] \ No newline at end of file +ArrayLike = typing.Union[typing.Tuple[T], typing.List[T], np.ndarray] From be723c737d0f3e13ea609b5a2d0dcd1f4ad41fbc Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 17:54:22 +0100 Subject: [PATCH 005/105] Update utils.py --- deeptrack/utils.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/deeptrack/utils.py b/deeptrack/utils.py index 32ee86241..825701d27 100644 --- a/deeptrack/utils.py +++ b/deeptrack/utils.py @@ -1,20 +1,24 @@ -""" Utility functions +"""Utility functions. -Defines a set of utility functions used throughout the code -to make it more readable. +This module defines utility functions that enhance code readability, +streamline common operations, and ensure type and argument consistency. Functions --------- -hasfunction(obj: any, function_name: str) -> bool - Return True if the object has a field named function_name - that is callable. Otherwise, return False. -isiterable(obj: any) +hasmethod(obj: any, method_name: str) -> bool + Return True if the object has a field named `function_name` that is + callable. Otherwise, return False. +isiterable(obj: any) -> bool Return True if the object is iterable. Else, return False. -as_list(obj: any) - If the input is iterable, convert it to list. +as_list(obj: any) -> list + If the input is iterable, convert it to list. Otherwise, wrap the input in a list. -get_kwarg_names(function: Callable) - Return the names of the keyword arguments the function accepts. +get_kwarg_names(function: Callable) -> List[str] + Retrieves the names of the keyword arguments accepted by a function. +kwarg_has_default(function: Callable, argument: str) -> bool + Checks if a specific argument of a function has a default value. +safe_call(function, positional_args=[], **kwargs) + Calls a function, passing only valid arguments from the provided kwargs. """ import inspect From 13d6f80b824bfc4b92199ba19e3b9036b9636840 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 18:07:15 +0100 Subject: [PATCH 006/105] Update utils.py --- deeptrack/utils.py | 91 +++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/deeptrack/utils.py b/deeptrack/utils.py index 825701d27..d862d68f1 100644 --- a/deeptrack/utils.py +++ b/deeptrack/utils.py @@ -19,47 +19,50 @@ Checks if a specific argument of a function has a default value. safe_call(function, positional_args=[], **kwargs) Calls a function, passing only valid arguments from the provided kwargs. + """ import inspect -from typing import Callable, List +from typing import Any, Callable, List def hasmethod(obj: any, method_name: str) -> bool: - """Check if an object has a callable method named method_name. + """Check if an object has a callable method named `method_name`. Parameters ---------- - obj - The object to be checked. - method_name + obj : any + The object to inspect. + method_name : str The name of the method to look for. Returns ------- bool - True if the object has an attribute method_name, and that - attribute is callable. + True if the object has an attribute named `method_name` that is + callable. """ - return hasattr(obj, method_name) and callable(getattr(obj, method_name, None)) + return (hasattr(obj, method_name) + and callable(getattr(obj, method_name, None))) def isiterable(obj: any) -> bool: - """Check if the input is iterable. - Note that this function does not capture all possible cases - and is subject to change in the future if issues arise. + """Determine if the input object is iterable. + + Note that this checks for the presence of a `.__next__()` method, which may + not cover all iterable objects. It could be updated if edge cases arise. Parameters ---------- - obj + obj : any The object to check. Returns ------- bool - True if the object has __next__ defined. + True if the object has `.__next__()` method. """ @@ -67,19 +70,20 @@ def isiterable(obj: any) -> bool: def as_list(obj: any) -> list: - """Ensure the input is a list. - If the input is iterable, convert it to a list, - otherwise wrap the input in a list. + """Ensure that the input is a list. + + Converts the input to a list if it is iterable; otherwise, it wraps it in a + list. Parameters ---------- - obj - The object that will be made a list. + obj : any + The object to be converted or wrapped in a list. Returns ------- list - The input as a list. + The input object as a list. """ @@ -90,19 +94,20 @@ def as_list(obj: any) -> list: def get_kwarg_names(function: Callable) -> List[str]: - """Retrieve the names of the keyword arguments. - Retrieve the names of the keyword arguments accepted by `function` - as a list of strings. + """Retrieve the names of the keyword arguments accepted by a function. + + Retrieves the names of the keyword arguments accepted by `function` as a + list of strings. Parameters ---------- - function - The function to retrieve keyword argument names from. + function : Callable + The function whose keyword argument names are to be retrieved. Returns ------- List[str] - The accepted keyword arguments as a list of strings. + A list of names of keyword arguments the function accepts. """ @@ -118,20 +123,22 @@ def get_kwarg_names(function: Callable) -> List[str]: def kwarg_has_default(function: Callable, argument: str) -> bool: - """Returns true if an argument has a default value. + """Check if a specific argument of a function has a default value. Parameters ---------- function : Callable - The function to check. + The function to inspect. argument : str - Name of the argument + Name of the argument to check. Returns ------- bool + True if the specified argument has a default value. """ + args = get_kwarg_names(function) if argument not in args: @@ -142,25 +149,35 @@ def kwarg_has_default(function: Callable, argument: str) -> bool: return len(args) - args.index(argument) <= len(defaults) -def safe_call(function, positional_args=[], **kwargs): - """Calls a function, using keyword arguments from a dictionary of arguments. - - If the function does not accept one of the argument provided, it will not - be passed. Does not support non-keyword arguments. +def safe_call(function, positional_args=[], **kwargs) -> Any: + """Calls a function with valid arguments from a dictionary of arguments. + + Filters `kwargs` to include only arguments accepted by the function, + ensuring that no invalid arguments are passed. This function also supports + positional arguments. Parameters ---------- function : Callable - The function to call - kwargs - Key-value pairs to draw input arguments from. + The function to call. + positional_args : list, optional + List of positional arguments to pass to the function. + kwargs : dict + Dictionary of keyword arguments to filter and pass. + + Returns + ------- + Any + The result of calling the function with the filtered arguments. + """ keys = get_kwarg_names(function) + # Filter kwargs to include only keys present in the function's signature. input_arguments = {} for key in keys: if key in kwargs: input_arguments[key] = kwargs[key] - return function(*positional_args, **input_arguments) + return function(*positional_args, **input_arguments) \ No newline at end of file From 0b4d19872bef4da382f6c1c4ec64aeda5e24ccd6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 23:31:22 +0100 Subject: [PATCH 007/105] Update test_utils.py --- deeptrack/test/test_utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index 84f4b98ce..515bcf2c4 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -1,13 +1,10 @@ -import sys - -# sys.path.append(".") # Adds the module to path - import unittest from .. import utils class TestUtils(unittest.TestCase): + def test_hasmethod(self): self.assertTrue(utils.hasmethod(utils, "hasmethod")) self.assertFalse( From e6468385e978961ef18d14a41e8a0c2999d5c0b9 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Thu, 5 Dec 2024 23:39:22 +0100 Subject: [PATCH 008/105] Update test_optics.py --- deeptrack/test/test_optics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeptrack/test/test_optics.py b/deeptrack/test/test_optics.py index 1828968fa..276696c8d 100644 --- a/deeptrack/test/test_optics.py +++ b/deeptrack/test/test_optics.py @@ -116,7 +116,7 @@ def test_upscale_fluorescence(self): error = np.abs( output_image_2x_upscale - output_image_no_upscale ).mean() # Mean absolute error - self.assertLess(error, 0.005) + self.assertLess(error, 0.01) def test_upscale_brightfield(self): microscope = optics.Fluorescence( From 6d65a5d35b17cbb57567b246d7561e20c9415d23 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 00:03:06 +0100 Subject: [PATCH 009/105] Update test_utils.py --- deeptrack/test/test_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index 515bcf2c4..6be25236f 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -21,7 +21,6 @@ def test_isiterable(self): self.assertTrue(utils.isiterable(iterable_obj)) def test_as_list(self): - obj = 1 self.assertEqual(utils.as_list(obj), [obj]) From c343ca0dc785b0ef1d2910e495253c58dcdb25a2 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 00:09:20 +0100 Subject: [PATCH 010/105] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fbb490095..5057588cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ pydata-sphinx-theme numpydoc scikit-image more_itertools -pint<0.20 +pint pandas tqdm lazy_import From 9d65eadd3e8c329819a4dcb38924f853ad68ca8e Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 00:15:16 +0100 Subject: [PATCH 011/105] Update optics.py --- deeptrack/optics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeptrack/optics.py b/deeptrack/optics.py index 29be92de5..c27c506e7 100644 --- a/deeptrack/optics.py +++ b/deeptrack/optics.py @@ -16,7 +16,7 @@ """ -from pint.quantity import Quantity +from pint import Quantity from deeptrack.backend.units import ( ConversionTable, create_context, From 0aa4363d40594761b57f81669aba904145d7aeaa Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 00:15:18 +0100 Subject: [PATCH 012/105] Update features.py --- deeptrack/features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeptrack/features.py b/deeptrack/features.py index edbc36b23..bd3691e3f 100644 --- a/deeptrack/features.py +++ b/deeptrack/features.py @@ -10,7 +10,7 @@ import random import numpy as np -from pint.quantity import Quantity +from pint import Quantity # import tensorflow as tf import skimage import skimage.measure From 77295d90ea5be3613b860f22b90b1857ba231df9 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe <46021832+giovannivolpe@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:03:39 +0100 Subject: [PATCH 013/105] Update requirements.txt --- requirements.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5057588cb..414aaa30a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,6 @@ numpy matplotlib scipy -Sphinx==2.2.0 -pydata-sphinx-theme -numpydoc scikit-image more_itertools pint @@ -11,4 +8,4 @@ pandas tqdm lazy_import rich -gdown \ No newline at end of file +gdown From 63604c5153efe4f05aa0e576d46fb1ebe3ab6c63 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:08:34 +0100 Subject: [PATCH 014/105] removed isiterable --- deeptrack/properties.py | 2 +- deeptrack/test/test_utils.py | 12 +++--------- deeptrack/utils.py | 21 --------------------- 3 files changed, 4 insertions(+), 31 deletions(-) diff --git a/deeptrack/properties.py b/deeptrack/properties.py index 5f84b068a..9e41bd82f 100644 --- a/deeptrack/properties.py +++ b/deeptrack/properties.py @@ -58,7 +58,7 @@ def create_action(self, sampling_rule, **dependencies): if isinstance(sampling_rule, (tuple, np.ndarray)): return lambda _ID=(): sampling_rule - if isiterable(sampling_rule): + if hasattr(sampling_rule, "__next__"): # If it's iterable, return the next value def wrapped_iterator(): while True: diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index 6be25236f..d45c7508f 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -10,15 +10,7 @@ def test_hasmethod(self): self.assertFalse( utils.hasmethod(utils, "this_is_definetely_not_a_method_of_utils") ) - - def test_isiterable(self): - self.assertFalse(utils.isiterable(1)) - - non_iterable_obj = ("apple", "banana", "cherry") - self.assertFalse(utils.isiterable(non_iterable_obj)) - - iterable_obj = iter(("apple", "banana", "cherry")) - self.assertTrue(utils.isiterable(iterable_obj)) + def test_as_list(self): obj = 1 @@ -27,6 +19,7 @@ def test_as_list(self): list_obj = [1, 2, 3] self.assertEqual(utils.as_list(list_obj), list_obj) + def test_get_kwarg_names(self): def func1(): pass @@ -63,6 +56,7 @@ def func7(key1, key2=1, key3=3, **kwargs): self.assertEqual(utils.get_kwarg_names(func7), ["key1", "key2", "key3"]) + def test_safe_call(self): arguments = { diff --git a/deeptrack/utils.py b/deeptrack/utils.py index d862d68f1..bc62fc250 100644 --- a/deeptrack/utils.py +++ b/deeptrack/utils.py @@ -48,27 +48,6 @@ def hasmethod(obj: any, method_name: str) -> bool: and callable(getattr(obj, method_name, None))) -def isiterable(obj: any) -> bool: - """Determine if the input object is iterable. - - Note that this checks for the presence of a `.__next__()` method, which may - not cover all iterable objects. It could be updated if edge cases arise. - - Parameters - ---------- - obj : any - The object to check. - - Returns - ------- - bool - True if the object has `.__next__()` method. - - """ - - return hasattr(obj, "__next__") - - def as_list(obj: any) -> list: """Ensure that the input is a list. From cc5cb1636a3fdc30b9f26e0cd0c228a49c8634df Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:09:54 +0100 Subject: [PATCH 015/105] Update utils.py --- deeptrack/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/deeptrack/utils.py b/deeptrack/utils.py index bc62fc250..cfd9d1567 100644 --- a/deeptrack/utils.py +++ b/deeptrack/utils.py @@ -8,8 +8,6 @@ hasmethod(obj: any, method_name: str) -> bool Return True if the object has a field named `function_name` that is callable. Otherwise, return False. -isiterable(obj: any) -> bool - Return True if the object is iterable. Else, return False. as_list(obj: any) -> list If the input is iterable, convert it to list. Otherwise, wrap the input in a list. From 1379acc2a6699a885e222874a2b89b1463fe57cc Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:09:56 +0100 Subject: [PATCH 016/105] Update utils_example.ipynb --- examples/module-examples/utils_example.ipynb | 528 +++++++++---------- 1 file changed, 249 insertions(+), 279 deletions(-) diff --git a/examples/module-examples/utils_example.ipynb b/examples/module-examples/utils_example.ipynb index 148d2261f..10c89b252 100644 --- a/examples/module-examples/utils_example.ipynb +++ b/examples/module-examples/utils_example.ipynb @@ -1,288 +1,258 @@ { - "cells": [ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: deeptrack in c:\\users\\gu\\deeptrack\\deeptrack-2.0 (1.2.1)\n", - "Requirement already satisfied: tensorflow in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (2.9.1)\n", - "Requirement already satisfied: tensorflow-probability in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.17.0)\n", - "Requirement already satisfied: numpy in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.23.0)\n", - "Requirement already satisfied: scipy in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.8.1)\n", - "Requirement already satisfied: pint in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.19.2)\n", - "Requirement already satisfied: pandas in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.4.3)\n", - "Requirement already satisfied: tqdm in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (4.64.0)\n", - "Requirement already satisfied: scikit-image>=0.18.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.19.3)\n", - "Requirement already satisfied: pydeepimagej in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.1.0)\n", - "Requirement already satisfied: more_itertools in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (8.13.0)\n", - "Requirement already satisfied: tensorflow_addons in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.17.1)\n", - "Requirement already satisfied: tifffile>=2019.7.26 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2022.5.4)\n", - "Requirement already satisfied: packaging>=20.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (21.3)\n", - "Requirement already satisfied: imageio>=2.4.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2.19.3)\n", - "Requirement already satisfied: pillow!=7.1.0,!=7.1.1,!=8.3.0,>=6.1.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (9.1.1)\n", - "Requirement already satisfied: networkx>=2.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2.8.4)\n", - "Requirement already satisfied: PyWavelets>=1.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (1.3.0)\n", - "Requirement already satisfied: python-dateutil>=2.8.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pandas->deeptrack) (2.8.2)\n", - "Requirement already satisfied: pytz>=2020.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pandas->deeptrack) (2022.1)\n", - "Requirement already satisfied: flatbuffers<2,>=1.12 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.12)\n", - "Requirement already satisfied: typing-extensions>=3.6.6 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (4.2.0)\n", - "Requirement already satisfied: termcolor>=1.1.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.0)\n", - "Requirement already satisfied: astunparse>=1.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.6.3)\n", - "Requirement already satisfied: gast<=0.4.0,>=0.2.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.4.0)\n", - "Requirement already satisfied: wrapt>=1.11.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.14.1)\n", - "Requirement already satisfied: protobuf<3.20,>=3.9.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.19.4)\n", - "Requirement already satisfied: absl-py>=1.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.0)\n", - "Requirement already satisfied: libclang>=13.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (14.0.1)\n", - "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.26.0)\n", - "Requirement already satisfied: google-pasta>=0.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.2.0)\n", - "Requirement already satisfied: h5py>=2.9.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.7.0)\n", - "Requirement already satisfied: six>=1.12.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.16.0)\n", - "Requirement already satisfied: keras-preprocessing>=1.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.2)\n", - "Requirement already satisfied: keras<2.10.0,>=2.9.0rc0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.0)\n", - "Requirement already satisfied: grpcio<2.0,>=1.24.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.47.0)\n", - "Requirement already satisfied: tensorboard<2.10,>=2.9 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.1)\n", - "Requirement already satisfied: setuptools in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (58.1.0)\n", - "Requirement already satisfied: tensorflow-estimator<2.10.0,>=2.9.0rc0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.0)\n", - "Requirement already satisfied: opt-einsum>=2.3.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.3.0)\n", - "Requirement already satisfied: typeguard>=2.7 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow_addons->deeptrack) (2.13.3)\n", - "Requirement already satisfied: cloudpickle>=1.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (2.1.0)\n", - "Requirement already satisfied: decorator in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (5.1.1)\n", - "Requirement already satisfied: dm-tree in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (0.1.7)\n", - "Requirement already satisfied: colorama in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tqdm->deeptrack) (0.4.5)\n", - "Requirement already satisfied: wheel<1.0,>=0.23.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from astunparse>=1.6.0->tensorflow->deeptrack) (0.37.1)\n", - "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from packaging>=20.0->scikit-image>=0.18.0->deeptrack) (3.0.9)\n", - "Requirement already satisfied: werkzeug>=1.0.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.1.2)\n", - "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.4.6)\n", - "Requirement already satisfied: google-auth<3,>=1.6.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.9.0)\n", - "Requirement already satisfied: requests<3,>=2.21.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.28.0)\n", - "Requirement already satisfied: markdown>=2.6.8 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.3.7)\n", - "Requirement already satisfied: tensorboard-data-server<0.7.0,>=0.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.6.1)\n", - "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.8.1)\n", - "Requirement already satisfied: cachetools<6.0,>=2.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (5.2.0)\n", - "Requirement already satisfied: rsa<5,>=3.1.4 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (4.8)\n", - "Requirement already satisfied: pyasn1-modules>=0.2.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.2.8)\n", - "Requirement already satisfied: requests-oauthlib>=0.7.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.3.1)\n", - "Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.26.9)\n", - "Requirement already satisfied: charset-normalizer~=2.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.0.12)\n", - "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2022.6.15)\n", - "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.3)\n", - "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.4.8)\n", - "Requirement already satisfied: oauthlib>=3.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.2.0)\n" - ] - } - ], - "source": [ - "%matplotlib inline\n", - "!pip install deeptrack" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# deeptrack.utils\n", - "\n", - "This example introduces the module deeptrack.properties.\n", - "\n", - "## What is contained in deeptrack.utils?\n", - "\n", - "The module deeptrack.utils contains utility functions that improve of the readability of the code and the quality of life of the programmer. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import deeptrack.utils as utils" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. utils.hasmethod()\n", - "\n", - "Checks if the input has a callable method named `method_name`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n", - "False\n", - "True\n" - ] - } - ], - "source": [ - "obj = [1] # a list \n", - "\n", - "print(utils.hasmethod(obj, \"my_func\")) # my_func is not an attribute of list\n", - "print(utils.hasmethod(obj, \"__doc__\")) # __doc__ is an attribute but not a function\n", - "print(utils.hasmethod(obj, \"append\")) # append is an attribute and a function" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. utils.isiterable()\n", - "\n", - "Checks if the input is iterable. Shorthand for `hasmethod(obj, '__next__')`. Contained in a function in case the definition should be exanded in the future." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "False\n", - "True\n" - ] - } - ], - "source": [ - "obj = [1]\n", - "\n", - "print(utils.isiterable(obj)) # a list is not iterable\n", - "print(utils.isiterable(iter(obj))) # Calling iter() makes the list iterable" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. utils.as_list()\n", - "\n", - "Converts input to list if possible, otherwise wraps it in a list." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 returns [1]\n", - "(1,) returns [1]\n", - "str returns ['s', 't', 'r']\n" - ] - } - ], - "source": [ - "print(1, \"returns\", utils.as_list(1))\n", - "print((1,), \"returns\", utils.as_list((1,)))\n", - "print(\"str\", \"returns\", utils.as_list(\"str\"))" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: deeptrack in c:\\users\\gu\\deeptrack\\deeptrack-2.0 (1.2.1)\n", + "Requirement already satisfied: tensorflow in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (2.9.1)\n", + "Requirement already satisfied: tensorflow-probability in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.17.0)\n", + "Requirement already satisfied: numpy in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.23.0)\n", + "Requirement already satisfied: scipy in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.8.1)\n", + "Requirement already satisfied: pint in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.19.2)\n", + "Requirement already satisfied: pandas in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.4.3)\n", + "Requirement already satisfied: tqdm in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (4.64.0)\n", + "Requirement already satisfied: scikit-image>=0.18.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.19.3)\n", + "Requirement already satisfied: pydeepimagej in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (1.1.0)\n", + "Requirement already satisfied: more_itertools in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (8.13.0)\n", + "Requirement already satisfied: tensorflow_addons in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from deeptrack) (0.17.1)\n", + "Requirement already satisfied: tifffile>=2019.7.26 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2022.5.4)\n", + "Requirement already satisfied: packaging>=20.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (21.3)\n", + "Requirement already satisfied: imageio>=2.4.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2.19.3)\n", + "Requirement already satisfied: pillow!=7.1.0,!=7.1.1,!=8.3.0,>=6.1.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (9.1.1)\n", + "Requirement already satisfied: networkx>=2.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (2.8.4)\n", + "Requirement already satisfied: PyWavelets>=1.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from scikit-image>=0.18.0->deeptrack) (1.3.0)\n", + "Requirement already satisfied: python-dateutil>=2.8.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pandas->deeptrack) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pandas->deeptrack) (2022.1)\n", + "Requirement already satisfied: flatbuffers<2,>=1.12 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.12)\n", + "Requirement already satisfied: typing-extensions>=3.6.6 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (4.2.0)\n", + "Requirement already satisfied: termcolor>=1.1.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.0)\n", + "Requirement already satisfied: astunparse>=1.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.6.3)\n", + "Requirement already satisfied: gast<=0.4.0,>=0.2.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.4.0)\n", + "Requirement already satisfied: wrapt>=1.11.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.14.1)\n", + "Requirement already satisfied: protobuf<3.20,>=3.9.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.19.4)\n", + "Requirement already satisfied: absl-py>=1.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.0)\n", + "Requirement already satisfied: libclang>=13.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (14.0.1)\n", + "Requirement already satisfied: tensorflow-io-gcs-filesystem>=0.23.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.26.0)\n", + "Requirement already satisfied: google-pasta>=0.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (0.2.0)\n", + "Requirement already satisfied: h5py>=2.9.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.7.0)\n", + "Requirement already satisfied: six>=1.12.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.16.0)\n", + "Requirement already satisfied: keras-preprocessing>=1.1.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.1.2)\n", + "Requirement already satisfied: keras<2.10.0,>=2.9.0rc0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.0)\n", + "Requirement already satisfied: grpcio<2.0,>=1.24.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (1.47.0)\n", + "Requirement already satisfied: tensorboard<2.10,>=2.9 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.1)\n", + "Requirement already satisfied: setuptools in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (58.1.0)\n", + "Requirement already satisfied: tensorflow-estimator<2.10.0,>=2.9.0rc0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (2.9.0)\n", + "Requirement already satisfied: opt-einsum>=2.3.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow->deeptrack) (3.3.0)\n", + "Requirement already satisfied: typeguard>=2.7 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow_addons->deeptrack) (2.13.3)\n", + "Requirement already satisfied: cloudpickle>=1.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (2.1.0)\n", + "Requirement already satisfied: decorator in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (5.1.1)\n", + "Requirement already satisfied: dm-tree in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorflow-probability->deeptrack) (0.1.7)\n", + "Requirement already satisfied: colorama in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tqdm->deeptrack) (0.4.5)\n", + "Requirement already satisfied: wheel<1.0,>=0.23.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from astunparse>=1.6.0->tensorflow->deeptrack) (0.37.1)\n", + "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from packaging>=20.0->scikit-image>=0.18.0->deeptrack) (3.0.9)\n", + "Requirement already satisfied: werkzeug>=1.0.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.1.2)\n", + "Requirement already satisfied: google-auth-oauthlib<0.5,>=0.4.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.4.6)\n", + "Requirement already satisfied: google-auth<3,>=1.6.3 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.9.0)\n", + "Requirement already satisfied: requests<3,>=2.21.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.28.0)\n", + "Requirement already satisfied: markdown>=2.6.8 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.3.7)\n", + "Requirement already satisfied: tensorboard-data-server<0.7.0,>=0.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.6.1)\n", + "Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.8.1)\n", + "Requirement already satisfied: cachetools<6.0,>=2.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (5.2.0)\n", + "Requirement already satisfied: rsa<5,>=3.1.4 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (4.8)\n", + "Requirement already satisfied: pyasn1-modules>=0.2.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.2.8)\n", + "Requirement already satisfied: requests-oauthlib>=0.7.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.3.1)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (1.26.9)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2.0.12)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (2022.6.15)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests<3,>=2.21.0->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.3)\n", + "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (0.4.8)\n", + "Requirement already satisfied: oauthlib>=3.0.0 in c:\\users\\gu\\appdata\\local\\programs\\python\\python310\\lib\\site-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<0.5,>=0.4.1->tensorboard<2.10,>=2.9->tensorflow->deeptrack) (3.2.0)\n" + ] + } + ], + "source": [ + "%matplotlib inline\n", + "!pip install deeptrack" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# deeptrack.utils\n", + "\n", + "This example introduces the module deeptrack.properties.\n", + "\n", + "## What is contained in deeptrack.utils?\n", + "\n", + "The module deeptrack.utils contains utility functions that improve of the readability of the code and the quality of life of the programmer. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import deeptrack.utils as utils" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. utils.hasmethod()\n", + "\n", + "Checks if the input has a callable method named `method_name`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. utils.get_kwarg_names()\n", - "\n", - "Returns the names of the keyword arguments that a function accepts." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "obj = [1] # a list \n", + "\n", + "print(utils.hasmethod(obj, \"my_func\")) # my_func is not an attribute of list\n", + "print(utils.hasmethod(obj, \"__doc__\")) # __doc__ is an attribute but not a function\n", + "print(utils.hasmethod(obj, \"append\")) # append is an attribute and a function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. utils.as_list()\n", + "\n", + "Converts input to list if possible, otherwise wraps it in a list." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['arg1', 'arg2', 'kwarg1', 'kwarg2']\n" - ] - } - ], - "source": [ - "def func1(arg1, arg2, kwarg1=None, kwarg2=1):\n", - " pass\n", - "\n", - "print(utils.get_kwarg_names(func1))" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "1 returns [1]\n", + "(1,) returns [1]\n", + "str returns ['s', 't', 'r']\n" + ] + } + ], + "source": [ + "print(1, \"returns\", utils.as_list(1))\n", + "print((1,), \"returns\", utils.as_list((1,)))\n", + "print(\"str\", \"returns\", utils.as_list(\"str\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. utils.get_kwarg_names()\n", + "\n", + "Returns the names of the keyword arguments that a function accepts." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['kwarg1', 'kwarg2']\n" - ] - } - ], - "source": [ - "def func2(arg1, arg2, *args, kwarg1=None, kwarg2=1, **kwargs):\n", - " pass\n", - "\n", - "print(utils.get_kwarg_names(func2))" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "['arg1', 'arg2', 'kwarg1', 'kwarg2']\n" + ] } - ], - "metadata": { - "file_extension": ".py", - "kernelspec": { - "display_name": "Python 3.8.6 64-bit", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.6" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": 3, - "vscode": { - "interpreter": { - "hash": "a44da721a5827f98cc9179544fef0a80b8a9b4f8cdc93722922a5386f263ab84" - } + ], + "source": [ + "def func1(arg1, arg2, kwarg1=None, kwarg2=1):\n", + " pass\n", + "\n", + "print(utils.get_kwarg_names(func1))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['kwarg1', 'kwarg2']\n" + ] } + ], + "source": [ + "def func2(arg1, arg2, *args, kwarg1=None, kwarg2=1, **kwargs):\n", + " pass\n", + "\n", + "print(utils.get_kwarg_names(func2))" + ] + } + ], + "metadata": { + "file_extension": ".py", + "kernelspec": { + "display_name": "Python 3.8.6 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.6" }, - "nbformat": 4, - "nbformat_minor": 2 + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3, + "vscode": { + "interpreter": { + "hash": "a44da721a5827f98cc9179544fef0a80b8a9b4f8cdc93722922a5386f263ab84" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } From 4e0ea40cb18467a20cca8e2b3fc32315a89650ea Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:14:55 +0100 Subject: [PATCH 017/105] Update properties.py --- deeptrack/properties.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deeptrack/properties.py b/deeptrack/properties.py index 9e41bd82f..61c378d0d 100644 --- a/deeptrack/properties.py +++ b/deeptrack/properties.py @@ -2,9 +2,7 @@ """ import numpy as np -from .utils import ( - isiterable, - get_kwarg_names, +from .utils import get_kwarg_names ) From 4f94e9801db60900fbdebd3b0948021b1b7548b0 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:15:38 +0100 Subject: [PATCH 018/105] Update utils.rst --- _src/source/utils.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/_src/source/utils.rst b/_src/source/utils.rst index 269004ac1..b42039790 100644 --- a/_src/source/utils.rst +++ b/_src/source/utils.rst @@ -21,11 +21,6 @@ hasmethod .. autofunction:: deeptrack.utils.hasmethod -isiterable -^^^^^^^^^^ - -.. autofunction:: deeptrack.utils.isiterable - kwarg_has_default ^^^^^^^^^^^^^^^^^ From 79fffda0755729aea9d2788b5b400bd450425de6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 18:21:53 +0100 Subject: [PATCH 019/105] Update python-app.yml --- .github/workflows/python-app.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 2d41b8a81..b02a0032f 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -15,13 +15,10 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, macos-latest, windows-latest] install-deeplay: ["", "deeplay"] - install-tensorflow: ["", "tensorflow"] - exclude: - - python-version: "3.11" - install-tensorflow: "tensorflow" + if: steps: - uses: actions/checkout@v3 @@ -38,10 +35,6 @@ jobs: if: ${{ matrix.install-deeplay == 'deeplay' }} run: | python -m pip install deeplay - - name: Install tensorflow - if: ${{ matrix.install-tensorflow == 'tensorflow' }} - run: | - python -m pip install tensorflow==2.10 tensorflow-probability tensorflow-datasets - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From eedf6e713a64510092020cdb6f175193c07d92d0 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 19:28:51 +0100 Subject: [PATCH 020/105] Update properties.py --- deeptrack/properties.py | 1 - 1 file changed, 1 deletion(-) diff --git a/deeptrack/properties.py b/deeptrack/properties.py index 61c378d0d..f5c75ebad 100644 --- a/deeptrack/properties.py +++ b/deeptrack/properties.py @@ -3,7 +3,6 @@ import numpy as np from .utils import get_kwarg_names -) from .backend.core import DeepTrackNode From 99b85261c44d432a2012917b487eeab944fbaef9 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 19:54:59 +0100 Subject: [PATCH 021/105] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index b02a0032f..85411b810 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -34,7 +34,7 @@ jobs: - name: Install deeplay if: ${{ matrix.install-deeplay == 'deeplay' }} run: | - python -m pip install deeplay + python -m pip install setuptools - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From 298bce0c83743c6427473f900666a0bd05a77893 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 19:56:30 +0100 Subject: [PATCH 022/105] Update python-app.yml --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 85411b810..b02a0032f 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -34,7 +34,7 @@ jobs: - name: Install deeplay if: ${{ matrix.install-deeplay == 'deeplay' }} run: | - python -m pip install setuptools + python -m pip install deeplay - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From 6d5f055a93a70545c77f33ea5c9d286d476debd8 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 19:57:49 +0100 Subject: [PATCH 023/105] Update __init__.py --- deeptrack/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 4203a44b8..5683c017e 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -7,7 +7,7 @@ units = UnitRegistry(pint_definitions.split("\n")) -# Check if tensorflow is installed without importing it +'''# Check if tensorflow is installed without importing it import pkg_resources installed = [pkg.key for pkg in pkg_resources.working_set] @@ -23,7 +23,7 @@ HAS_TORCH = False if HAS_TENSORFLOW and HAS_TORCH: - import torch # torch must be imported before tensorflow + import torch # torch must be imported before tensorflow''' from deeptrack.features import * from deeptrack.aberrations import * From 3393ded505313fdf276ccd3e8bea53496360b124 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 20:06:26 +0100 Subject: [PATCH 024/105] removed pkg_resources --- deeptrack/__init__.py | 2 +- deeptrack/models/utils.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 5683c017e..1ce5ebfe6 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -23,7 +23,7 @@ HAS_TORCH = False if HAS_TENSORFLOW and HAS_TORCH: - import torch # torch must be imported before tensorflow''' + import torch # torch must be imported before tensorflow'''#TBE from deeptrack.features import * from deeptrack.aberrations import * diff --git a/deeptrack/models/utils.py b/deeptrack/models/utils.py index 50724fa84..f56769ada 100644 --- a/deeptrack/models/utils.py +++ b/deeptrack/models/utils.py @@ -21,9 +21,9 @@ ImportWarning, ) -import pkg_resources +'''import pkg_resources -installed_pkg = [pkg.key for pkg in pkg_resources.working_set] +installed_pkg = [pkg.key for pkg in pkg_resources.working_set]'''#TBE __all__ = [ "compile", @@ -96,8 +96,8 @@ def _get_norm_by_name(x): """Returns a normalization layer by name.""" if hasattr(layers, x): return getattr(layers, x) - elif "tensorflow-addons" in installed_pkg and hasattr(tfa.layers, x): - return getattr(tfa.layers, x) + '''elif "tensorflow-addons" in installed_pkg and hasattr(tfa.layers, x): + return getattr(tfa.layers, x)'''#TBE else: raise ValueError(f"Unknown normalization {x}.") From 0277bae99eca67d7bede16e520a4636c79c5ca62 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 21:45:42 +0100 Subject: [PATCH 025/105] Update __init__.py --- deeptrack/__init__.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 1ce5ebfe6..858b16fcd 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -1,11 +1,22 @@ # flake8: noqa -from pint import UnitRegistry, Context -from .backend.pint_definition import pint_definitions import lazy_import -import importlib +from pint import UnitRegistry +'''units = UnitRegistry(pint_definitions.split("\n"))'''#TBE -units = UnitRegistry(pint_definitions.split("\n")) +# Create a UnitRegistry and add custom units. +units = UnitRegistry() +custom_units = [ + "pixel = 1 micrometer = px", ### Can this be erased? + "xpixel = 1 micrometer = xpx", ### why these are defined as 1 um? + "ypixel = 1 micrometer = ypx", + "zpixel = 1 micrometer = zpx", + "simulation_xpixel = 1 micrometer = sxpx", + "simulation_ypixel = 1 micrometer = sypx", + "simulation_zpixel = 1 micrometer = szpx" +] +for unit in custom_units: + units.define(unit) '''# Check if tensorflow is installed without importing it import pkg_resources From 4217249d471a7ebe3a28497b5d91e55ca051cac8 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 21:45:45 +0100 Subject: [PATCH 026/105] Delete pint_definition.py --- deeptrack/backend/pint_definition.py | 943 --------------------------- 1 file changed, 943 deletions(-) delete mode 100644 deeptrack/backend/pint_definition.py diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py deleted file mode 100644 index f8137bd07..000000000 --- a/deeptrack/backend/pint_definition.py +++ /dev/null @@ -1,943 +0,0 @@ -pint_constants = """ -# Default Pint constants definition file -# Based on the International System of Units -# Language: english -# Source: https://physics.nist.gov/cuu/Constants/ -# https://physics.nist.gov/PhysRefData/XrayTrans/Html/search.html -# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. - -#### MATHEMATICAL CONSTANTS #### -# As computed by Maxima with fpprec:50 - -pi = 3.1415926535897932384626433832795028841971693993751 = π # pi -tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian -ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 -wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 -wien_u = 2.8214393721220788934031913302944851953458817440731 # solution to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3 -eulers_number = 2.71828182845904523536028747135266249775724709369995 - -#### DEFINED EXACT CONSTANTS #### - -speed_of_light = 299792458 m/s = c = c_0 # since 1983 -planck_constant = 6.62607015e-34 J s = h # since May 2019 -elementary_charge = 1.602176634e-19 C = e # since May 2019 -avogadro_number = 6.02214076e23 # since May 2019 -boltzmann_constant = 1.380649e-23 J K^-1 = k = k_B # since May 2019 -standard_gravity = 9.80665 m/s^2 = g_0 = g0 = g_n = gravity # since 1901 -standard_atmosphere = 1.01325e5 Pa = atm = atmosphere # since 1954 -conventional_josephson_constant = 4.835979e14 Hz / V = K_J90 # since Jan 1990 -conventional_von_klitzing_constant = 2.5812807e4 ohm = R_K90 # since Jan 1990 - -#### DERIVED EXACT CONSTANTS #### -# Floating-point conversion may introduce inaccuracies - -zeta = c / (cm/s) = ζ -dirac_constant = h / (2 * π) = ħ = hbar = atomic_unit_of_action = a_u_action -avogadro_constant = avogadro_number * mol^-1 = N_A -molar_gas_constant = k * N_A = R -faraday_constant = e * N_A -conductance_quantum = 2 * e ** 2 / h = G_0 -magnetic_flux_quantum = h / (2 * e) = Φ_0 = Phi_0 -josephson_constant = 2 * e / h = K_J -von_klitzing_constant = h / e ** 2 = R_K -stefan_boltzmann_constant = 2 / 15 * π ** 5 * k ** 4 / (h ** 3 * c ** 2) = σ = sigma -first_radiation_constant = 2 * π * h * c ** 2 = c_1 -second_radiation_constant = h * c / k = c_2 -wien_wavelength_displacement_law_constant = h * c / (k * wien_x) -wien_frequency_displacement_law_constant = wien_u * k / h - -#### MEASURED CONSTANTS #### -# Recommended CODATA-2018 values -# To some extent, what is measured and what is derived is a bit arbitrary. -# The choice of measured constants is based on convenience and on available uncertainty. -# The uncertainty in the last significant digits is given in parentheses as a comment. - -newtonian_constant_of_gravitation = 6.67430e-11 m^3/(kg s^2) = _ = gravitational_constant # (15) -rydberg_constant = 1.0973731568160e7 * m^-1 = R_∞ = R_inf # (21) -electron_g_factor = -2.00231930436256 = g_e # (35) -atomic_mass_constant = 1.66053906660e-27 kg = m_u # (50) -electron_mass = 9.1093837015e-31 kg = m_e = atomic_unit_of_mass = a_u_mass # (28) -proton_mass = 1.67262192369e-27 kg = m_p # (51) -neutron_mass = 1.67492749804e-27 kg = m_n # (95) -lattice_spacing_of_Si = 1.920155716e-10 m = d_220 # (32) -K_alpha_Cu_d_220 = 0.80232719 # (22) -K_alpha_Mo_d_220 = 0.36940604 # (19) -K_alpha_W_d_220 = 0.108852175 # (98) - -#### DERIVED CONSTANTS #### - -fine_structure_constant = (2 * h * R_inf / (m_e * c)) ** 0.5 = α = alpha -vacuum_permeability = 2 * α * h / (e ** 2 * c) = µ_0 = mu_0 = mu0 = magnetic_constant -vacuum_permittivity = e ** 2 / (2 * α * h * c) = ε_0 = epsilon_0 = eps_0 = eps0 = electric_constant -impedance_of_free_space = 2 * α * h / e ** 2 = Z_0 = characteristic_impedance_of_vacuum -coulomb_constant = α * hbar * c / e ** 2 = k_C -classical_electron_radius = α * hbar / (m_e * c) = r_e -thomson_cross_section = 8 / 3 * π * r_e ** 2 = σ_e = sigma_e -""" - -pint_definitions = f""" -# Default Pint units definition file -# Based on the International System of Units -# Language: english -# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. - -# Syntax -# ====== -# Units -# ----- -# = [= ] [= ] [ = ] [...] -# -# The canonical name and aliases should be expressed in singular form. -# Pint automatically deals with plurals built by adding 's' to the singular form; plural -# forms that don't follow this rule should be instead explicitly listed as aliases. -# -# If a unit has no symbol and one wants to define aliases, then the symbol should be -# conventionally set to _. -# -# Example: -# millennium = 1e3 * year = _ = millennia -# -# -# Prefixes -# -------- -# - = [= ] [= ] [ = ] [...] -# -# Example: -# deca- = 1e+1 = da- = deka- -# -# -# Derived dimensions -# ------------------ -# [dimension name] = -# -# Example: -# [density] = [mass] / [volume] -# -# Note that primary dimensions don't need to be declared; they can be -# defined for the first time in a unit definition. -# E.g. see below `meter = [length]` -# -# -# Additional aliases -# ------------------ -# @alias = [ = ] [...] -# -# Used to add aliases to already existing unit definitions. -# Particularly useful when one wants to enrich definitions -# from defaults_en.txt with custom aliases. -# -# Example: -# @alias meter = my_meter - -# See also: https://pint.readthedocs.io/en/latest/defining.html - -@defaults - group = international - system = mks -@end - - -#### PREFIXES #### - -# decimal prefixes -yocto- = 1e-24 = y- -zepto- = 1e-21 = z- -atto- = 1e-18 = a- -femto- = 1e-15 = f- -pico- = 1e-12 = p- -nano- = 1e-9 = n- -micro- = 1e-6 = µ- = u- -milli- = 1e-3 = m- -centi- = 1e-2 = c- -deci- = 1e-1 = d- -deca- = 1e+1 = da- = deka- -hecto- = 1e2 = h- -kilo- = 1e3 = k- -mega- = 1e6 = M- -giga- = 1e9 = G- -tera- = 1e12 = T- -peta- = 1e15 = P- -exa- = 1e18 = E- -zetta- = 1e21 = Z- -yotta- = 1e24 = Y- - -# binary_prefixes -kibi- = 2**10 = Ki- -mebi- = 2**20 = Mi- -gibi- = 2**30 = Gi- -tebi- = 2**40 = Ti- -pebi- = 2**50 = Pi- -exbi- = 2**60 = Ei- -zebi- = 2**70 = Zi- -yobi- = 2**80 = Yi- - -# extra_prefixes -semi- = 0.5 = _ = demi- -sesqui- = 1.5 - - -#### BASE UNITS #### - -meter = [length] = m = metre -second = [time] = s = sec -ampere = [current] = A = amp -candela = [luminosity] = cd = candle -gram = [mass] = g -mole = [substance] = mol -kelvin = [temperature]; offset: 0 = K = degK = °K = degree_Kelvin = degreeK # older names supported for compatibility -radian = [] = rad -bit = [] -count = [] - - -#### CONSTANTS #### - -{pint_constants} - - -#### UNITS #### -# Common and less common, grouped by quantity. -# Conversion factors are exact (except when noted), -# although floating-point conversion may introduce inaccuracies - -# Angle -turn = 2 * π * radian = _ = revolution = cycle = circle -degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree -arcminute = degree / 60 = arcmin = arc_minute = angular_minute -arcsecond = arcminute / 60 = arcsec = arc_second = angular_second -milliarcsecond = 1e-3 * arcsecond = mas -grade = π / 200 * radian = grad = gon -mil = π / 32000 * radian - -# Solid angle -steradian = radian ** 2 = sr -square_degree = (π / 180) ** 2 * sr = sq_deg = sqdeg - -# Information -baud = bit / second = Bd = bps - -byte = 8 * bit = B = octet -# byte = 8 * bit = _ = octet -## NOTE: B (byte) symbol can conflict with Bell - -# Length -angstrom = 1e-10 * meter = Å = ångström = Å -micron = micrometer = µ -fermi = femtometer = fm -light_year = speed_of_light * julian_year = ly = lightyear -astronomical_unit = 149597870700 * meter = au # since Aug 2012 -parsec = 1 / tansec * astronomical_unit = pc -nautical_mile = 1852 * meter = nmi -bohr = hbar / (alpha * m_e * c) = a_0 = a0 = bohr_radius = atomic_unit_of_length = a_u_length -x_unit_Cu = K_alpha_Cu_d_220 * d_220 / 1537.4 = Xu_Cu -x_unit_Mo = K_alpha_Mo_d_220 * d_220 / 707.831 = Xu_Mo -angstrom_star = K_alpha_W_d_220 * d_220 / 0.2090100 = Å_star -planck_length = (hbar * gravitational_constant / c ** 3) ** 0.5 - -# Mass -metric_ton = 1e3 * kilogram = t = tonne -unified_atomic_mass_unit = atomic_mass_constant = u = amu -dalton = atomic_mass_constant = Da -grain = 64.79891 * milligram = gr -gamma_mass = microgram -carat = 200 * milligram = ct = karat -planck_mass = (hbar * c / gravitational_constant) ** 0.5 - -# Time -minute = 60 * second = min -hour = 60 * minute = hr -day = 24 * hour = d -week = 7 * day -fortnight = 2 * week -year = 365.25 * day = a = yr = julian_year -month = year / 12 - -# decade = 10 * year -## NOTE: decade [time] can conflict with decade [dimensionless] - -century = 100 * year = _ = centuries -millennium = 1e3 * year = _ = millennia -eon = 1e9 * year -shake = 1e-8 * second -svedberg = 1e-13 * second -atomic_unit_of_time = hbar / E_h = a_u_time -gregorian_year = 365.2425 * day -sidereal_year = 365.256363004 * day # approximate, as of J2000 epoch -tropical_year = 365.242190402 * day # approximate, as of J2000 epoch -common_year = 365 * day -leap_year = 366 * day -sidereal_day = day / 1.00273790935079524 # approximate -sidereal_month = 27.32166155 * day # approximate -tropical_month = 27.321582 * day # approximate -synodic_month = 29.530589 * day = _ = lunar_month # approximate -planck_time = (hbar * gravitational_constant / c ** 5) ** 0.5 - -# Temperature -degree_Celsius = kelvin; offset: 273.15 = °C = celsius = degC = degreeC -degree_Rankine = 5 / 9 * kelvin; offset: 0 = °R = rankine = degR = degreeR -degree_Fahrenheit = 5 / 9 * kelvin; offset: 233.15 + 200 / 9 = °F = fahrenheit = degF = degreeF -degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degreeRe = degree_Réaumur = réaumur -atomic_unit_of_temperature = E_h / k = a_u_temp -planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5 - -# Area -[area] = [length] ** 2 -are = 100 * meter ** 2 -barn = 1e-28 * meter ** 2 = b -darcy = centipoise * centimeter ** 2 / (second * atmosphere) -hectare = 100 * are = ha - -# Volume -[volume] = [length] ** 3 -liter = decimeter ** 3 = l = L = litre -cubic_centimeter = centimeter ** 3 = cc -lambda = microliter = λ -stere = meter ** 3 - -# Frequency -[frequency] = 1 / [time] -hertz = 1 / second = Hz -revolutions_per_minute = revolution / minute = rpm -revolutions_per_second = revolution / second = rps -counts_per_second = count / second = cps - -# Wavenumber -[wavenumber] = 1 / [length] -reciprocal_centimeter = 1 / cm = cm_1 = kayser - -# Velocity -[velocity] = [length] / [time] -[speed] = [velocity] -knot = nautical_mile / hour = kt = knot_international = international_knot -mile_per_hour = mile / hour = mph = MPH -kilometer_per_hour = kilometer / hour = kph = KPH -kilometer_per_second = kilometer / second = kps -meter_per_second = meter / second = mps -foot_per_second = foot / second = fps - -# Acceleration -[acceleration] = [velocity] / [time] -galileo = centimeter / second ** 2 = Gal - -# Force -[force] = [mass] * [acceleration] -newton = kilogram * meter / second ** 2 = N -dyne = gram * centimeter / second ** 2 = dyn -force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond -force_gram = g_0 * gram = gf = gram_force -force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force -atomic_unit_of_force = E_h / a_0 = a_u_force - -# Energy -[energy] = [force] * [length] -joule = newton * meter = J -erg = dyne * centimeter -watt_hour = watt * hour = Wh = watthour -electron_volt = e * volt = eV -rydberg = h * c * R_inf = Ry -hartree = 2 * rydberg = E_h = Eh = hartree_energy = atomic_unit_of_energy = a_u_energy -calorie = 4.184 * joule = cal = thermochemical_calorie = cal_th -international_calorie = 4.1868 * joule = cal_it = international_steam_table_calorie -fifteen_degree_calorie = 4.1855 * joule = cal_15 -british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso -international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it -thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th -quadrillion_Btu = 1e15 * Btu = quad -therm = 1e5 * Btu = thm = EC_therm -US_therm = 1.054804e8 * joule # approximate, no exact definition -ton_TNT = 1e9 * calorie = tTNT -tonne_of_oil_equivalent = 1e10 * international_calorie = toe -atmosphere_liter = atmosphere * liter = atm_l - -# Power -[power] = [energy] / [time] -watt = joule / second = W -volt_ampere = volt * ampere = VA -horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower -boiler_horsepower = 33475 * Btu / hour # unclear which Btu -metric_horsepower = 75 * force_kilogram * meter / second -electrical_horsepower = 746 * watt -refrigeration_ton = 12e3 * Btu / hour = _ = ton_of_refrigeration # approximate, no exact definition -standard_liter_per_minute = atmosphere * liter / minute = slpm = slm -conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90 - -# Momentum -[momentum] = [length] * [mass] / [time] - -# Density (as auxiliary for pressure) -[density] = [mass] / [volume] -mercury = 13.5951 * kilogram / liter = Hg = Hg_0C = Hg_32F = conventional_mercury -water = 1.0 * kilogram / liter = H2O = conventional_water -mercury_60F = 13.5568 * kilogram / liter = Hg_60F # approximate -water_39F = 0.999972 * kilogram / liter = water_4C # approximate -water_60F = 0.999001 * kilogram / liter # approximate - -# Pressure -[pressure] = [force] / [area] -pascal = newton / meter ** 2 = Pa -barye = dyne / centimeter ** 2 = Ba = barie = barad = barrie = baryd -bar = 1e5 * pascal -technical_atmosphere = kilogram * g_0 / centimeter ** 2 = at -torr = atm / 760 -pound_force_per_square_inch = force_pound / inch ** 2 = psi -kip_per_square_inch = kip / inch ** 2 = ksi -millimeter_Hg = millimeter * Hg * g_0 = mmHg = mm_Hg = millimeter_Hg_0C -centimeter_Hg = centimeter * Hg * g_0 = cmHg = cm_Hg = centimeter_Hg_0C -inch_Hg = inch * Hg * g_0 = inHg = in_Hg = inch_Hg_32F -inch_Hg_60F = inch * Hg_60F * g_0 -inch_H2O_39F = inch * water_39F * g_0 -inch_H2O_60F = inch * water_60F * g_0 -foot_H2O = foot * water * g_0 = ftH2O = feet_H2O -centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O -sound_pressure_level = 20e-6 * pascal = SPL - -# Torque -[torque] = [force] * [length] -foot_pound = foot * force_pound = ft_lb = footpound - -# Viscosity -[viscosity] = [pressure] * [time] -poise = 0.1 * Pa * second = P -reyn = psi * second - -# Kinematic viscosity -[kinematic_viscosity] = [area] / [time] -stokes = centimeter ** 2 / second = St - -# Fluidity -[fluidity] = 1 / [viscosity] -rhe = 1 / poise - -# Amount of substance -particle = 1 / N_A = _ = molec = molecule - -# Concentration -[concentration] = [substance] / [volume] -molar = mole / liter = M - -# Catalytic activity -[activity] = [substance] / [time] -katal = mole / second = kat -enzyme_unit = micromole / minute = U = enzymeunit - -# Entropy -[entropy] = [energy] / [temperature] -clausius = calorie / kelvin = Cl - -# Molar entropy -[molar_entropy] = [entropy] / [substance] -entropy_unit = calorie / kelvin / mole = eu - -# Radiation -becquerel = counts_per_second = Bq -curie = 3.7e10 * becquerel = Ci -rutherford = 1e6 * becquerel = Rd -gray = joule / kilogram = Gy -sievert = joule / kilogram = Sv -rads = 0.01 * gray -rem = 0.01 * sievert -roentgen = 2.58e-4 * coulomb / kilogram = _ = röntgen # approximate, depends on medium - -# Heat transimission -[heat_transmission] = [energy] / [area] -peak_sun_hour = 1e3 * watt_hour / meter ** 2 = PSH -langley = thermochemical_calorie / centimeter ** 2 = Ly - -# Luminance -[luminance] = [luminosity] / [area] -nit = candela / meter ** 2 -stilb = candela / centimeter ** 2 -lambert = 1 / π * candela / centimeter ** 2 - -# Luminous flux -[luminous_flux] = [luminosity] -lumen = candela * steradian = lm - -# Illuminance -[illuminance] = [luminous_flux] / [area] -lux = lumen / meter ** 2 = lx - -# Intensity -[intensity] = [power] / [area] -atomic_unit_of_intensity = 0.5 * ε_0 * c * atomic_unit_of_electric_field ** 2 = a_u_intensity - -# Current -biot = 10 * ampere = Bi -abampere = biot = abA -atomic_unit_of_current = e / atomic_unit_of_time = a_u_current -mean_international_ampere = mean_international_volt / mean_international_ohm = A_it -US_international_ampere = US_international_volt / US_international_ohm = A_US -conventional_ampere_90 = K_J90 * R_K90 / (K_J * R_K) * ampere = A_90 -planck_current = (c ** 6 / gravitational_constant / k_C) ** 0.5 - -# Charge -[charge] = [current] * [time] -coulomb = ampere * second = C -abcoulomb = 10 * C = abC -faraday = e * N_A * mole -conventional_coulomb_90 = K_J90 * R_K90 / (K_J * R_K) * coulomb = C_90 -ampere_hour = ampere * hour = Ah - -# Electric potential -[electric_potential] = [energy] / [charge] -volt = joule / coulomb = V -abvolt = 1e-8 * volt = abV -mean_international_volt = 1.00034 * volt = V_it # approximate -US_international_volt = 1.00033 * volt = V_US # approximate -conventional_volt_90 = K_J90 / K_J * volt = V_90 - -# Electric field -[electric_field] = [electric_potential] / [length] -atomic_unit_of_electric_field = e * k_C / a_0 ** 2 = a_u_electric_field - -# Electric displacement field -[electric_displacement_field] = [charge] / [area] - -# Resistance -[resistance] = [electric_potential] / [current] -ohm = volt / ampere = Ω -abohm = 1e-9 * ohm = abΩ -mean_international_ohm = 1.00049 * ohm = Ω_it = ohm_it # approximate -US_international_ohm = 1.000495 * ohm = Ω_US = ohm_US # approximate -conventional_ohm_90 = R_K / R_K90 * ohm = Ω_90 = ohm_90 - -# Resistivity -[resistivity] = [resistance] * [length] - -# Conductance -[conductance] = [current] / [electric_potential] -siemens = ampere / volt = S = mho -absiemens = 1e9 * siemens = abS = abmho - -# Capacitance -[capacitance] = [charge] / [electric_potential] -farad = coulomb / volt = F -abfarad = 1e9 * farad = abF -conventional_farad_90 = R_K90 / R_K * farad = F_90 - -# Inductance -[inductance] = [magnetic_flux] / [current] -henry = weber / ampere = H -abhenry = 1e-9 * henry = abH -conventional_henry_90 = R_K / R_K90 * henry = H_90 - -# Magnetic flux -[magnetic_flux] = [electric_potential] * [time] -weber = volt * second = Wb -unit_pole = µ_0 * biot * centimeter - -# Magnetic field -[magnetic_field] = [magnetic_flux] / [area] -tesla = weber / meter ** 2 = T -gamma = 1e-9 * tesla = γ - -# Magnetomotive force -[magnetomotive_force] = [current] -ampere_turn = ampere = At -biot_turn = biot -gilbert = 1 / (4 * π) * biot_turn = Gb - -# Magnetic field strength -[magnetic_field_strength] = [current] / [length] - -# Electric dipole moment -[electric_dipole] = [charge] * [length] -debye = 1e-9 / ζ * coulomb * angstrom = D # formally 1 D = 1e-10 Fr*Å, but we generally want to use it outside the Gaussian context - -# Electric quadrupole moment -[electric_quadrupole] = [charge] * [area] -buckingham = debye * angstrom - -# Magnetic dipole moment -[magnetic_dipole] = [current] * [area] -bohr_magneton = e * hbar / (2 * m_e) = µ_B = mu_B -nuclear_magneton = e * hbar / (2 * m_p) = µ_N = mu_N - -# Logaritmic Unit Definition -# Unit = scale; logbase; logfactor -# x_dB = [logfactor] * log( x_lin / [scale] ) / log( [logbase] ) - -# Logaritmic Units of dimensionless quantity: [ https://en.wikipedia.org/wiki/Level_(logarithmic_quantity) ] - -decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm -decibelmicrowatt = 1e-6 watt; logbase: 10; logfactor: 10 = dBu - -decibel = 1 ; logbase: 10; logfactor: 10 = dB -# bell = 1 ; logbase: 10; logfactor: = B -## NOTE: B (Bell) symbol conflicts with byte - -decade = 1 ; logbase: 10; logfactor: 1 -## NOTE: decade [time] can conflict with decade [dimensionless] - -octave = 1 ; logbase: 2; logfactor: 1 = oct - -neper = 1 ; logbase: 2.71828182845904523536028747135266249775724709369995; logfactor: 0.5 = Np -# neper = 1 ; logbase: eulers_number; logfactor: 0.5 = Np - -#### UNIT GROUPS #### -# Mostly for length, area, volume, mass, force -# (customary or specialized units) - -@group USCSLengthInternational - thou = 1e-3 * inch = th = mil_length - inch = yard / 36 = in = international_inch = inches = international_inches - hand = 4 * inch - foot = yard / 3 = ft = international_foot = feet = international_feet - yard = 0.9144 * meter = yd = international_yard # since Jul 1959 - mile = 1760 * yard = mi = international_mile - - circular_mil = π / 4 * mil_length ** 2 = cmil - square_inch = inch ** 2 = sq_in = square_inches - square_foot = foot ** 2 = sq_ft = square_feet - square_yard = yard ** 2 = sq_yd - square_mile = mile ** 2 = sq_mi - - cubic_inch = in ** 3 = cu_in - cubic_foot = ft ** 3 = cu_ft = cubic_feet - cubic_yard = yd ** 3 = cu_yd -@end - -@group USCSLengthSurvey - link = 1e-2 * chain = li = survey_link - survey_foot = 1200 / 3937 * meter = sft - fathom = 6 * survey_foot - rod = 16.5 * survey_foot = rd = pole = perch - chain = 4 * rod - furlong = 40 * rod = fur - cables_length = 120 * fathom - survey_mile = 5280 * survey_foot = smi = us_statute_mile - league = 3 * survey_mile - - square_rod = rod ** 2 = sq_rod = sq_pole = sq_perch - acre = 10 * chain ** 2 - square_survey_mile = survey_mile ** 2 = _ = section - square_league = league ** 2 - - acre_foot = acre * survey_foot = _ = acre_feet -@end - -@group USCSDryVolume - dry_pint = bushel / 64 = dpi = US_dry_pint - dry_quart = bushel / 32 = dqt = US_dry_quart - dry_gallon = bushel / 8 = dgal = US_dry_gallon - peck = bushel / 4 = pk - bushel = 2150.42 cubic_inch = bu - dry_barrel = 7056 cubic_inch = _ = US_dry_barrel - board_foot = ft * ft * in = FBM = board_feet = BF = BDFT = super_foot = superficial_foot = super_feet = superficial_feet -@end - -@group USCSLiquidVolume - minim = pint / 7680 - fluid_dram = pint / 128 = fldr = fluidram = US_fluid_dram = US_liquid_dram - fluid_ounce = pint / 16 = floz = US_fluid_ounce = US_liquid_ounce - gill = pint / 4 = gi = liquid_gill = US_liquid_gill - pint = quart / 2 = pt = liquid_pint = US_pint - fifth = gallon / 5 = _ = US_liquid_fifth - quart = gallon / 4 = qt = liquid_quart = US_liquid_quart - gallon = 231 * cubic_inch = gal = liquid_gallon = US_liquid_gallon -@end - -@group USCSVolumeOther - teaspoon = fluid_ounce / 6 = tsp - tablespoon = fluid_ounce / 2 = tbsp - shot = 3 * tablespoon = jig = US_shot - cup = pint / 2 = cp = liquid_cup = US_liquid_cup - barrel = 31.5 * gallon = bbl - oil_barrel = 42 * gallon = oil_bbl - beer_barrel = 31 * gallon = beer_bbl - hogshead = 63 * gallon -@end - -@group Avoirdupois - dram = pound / 256 = dr = avoirdupois_dram = avdp_dram = drachm - ounce = pound / 16 = oz = avoirdupois_ounce = avdp_ounce - pound = 7e3 * grain = lb = avoirdupois_pound = avdp_pound - stone = 14 * pound - quarter = 28 * stone - bag = 94 * pound - hundredweight = 100 * pound = cwt = short_hundredweight - long_hundredweight = 112 * pound - ton = 2e3 * pound = _ = short_ton - long_ton = 2240 * pound - slug = g_0 * pound * second ** 2 / foot - slinch = g_0 * pound * second ** 2 / inch = blob = slugette - - force_ounce = g_0 * ounce = ozf = ounce_force - force_pound = g_0 * pound = lbf = pound_force - force_ton = g_0 * ton = _ = ton_force = force_short_ton = short_ton_force - force_long_ton = g_0 * long_ton = _ = long_ton_force - kip = 1e3 * force_pound - poundal = pound * foot / second ** 2 = pdl -@end - -@group AvoirdupoisUK using Avoirdupois - UK_hundredweight = long_hundredweight = UK_cwt - UK_ton = long_ton - UK_force_ton = force_long_ton = _ = UK_ton_force -@end - -@group AvoirdupoisUS using Avoirdupois - US_hundredweight = hundredweight = US_cwt - US_ton = ton - US_force_ton = force_ton = _ = US_ton_force -@end - -@group Troy - pennyweight = 24 * grain = dwt - troy_ounce = 480 * grain = toz = ozt - troy_pound = 12 * troy_ounce = tlb = lbt -@end - -@group Apothecary - scruple = 20 * grain - apothecary_dram = 3 * scruple = ap_dr - apothecary_ounce = 8 * apothecary_dram = ap_oz - apothecary_pound = 12 * apothecary_ounce = ap_lb -@end - -@group ImperialVolume - imperial_minim = imperial_fluid_ounce / 480 - imperial_fluid_scruple = imperial_fluid_ounce / 24 - imperial_fluid_drachm = imperial_fluid_ounce / 8 = imperial_fldr = imperial_fluid_dram - imperial_fluid_ounce = imperial_pint / 20 = imperial_floz = UK_fluid_ounce - imperial_gill = imperial_pint / 4 = imperial_gi = UK_gill - imperial_cup = imperial_pint / 2 = imperial_cp = UK_cup - imperial_pint = imperial_gallon / 8 = imperial_pt = UK_pint - imperial_quart = imperial_gallon / 4 = imperial_qt = UK_quart - imperial_gallon = 4.54609 * liter = imperial_gal = UK_gallon - imperial_peck = 2 * imperial_gallon = imperial_pk = UK_pk - imperial_bushel = 8 * imperial_gallon = imperial_bu = UK_bushel - imperial_barrel = 36 * imperial_gallon = imperial_bbl = UK_bbl -@end - -@group Textile - tex = gram / kilometer = Tt - dtex = decitex - denier = gram / (9 * kilometer) = den = Td - jute = pound / (14400 * yard) = Tj - aberdeen = jute = Ta - RKM = gf / tex - - number_english = 840 * yard / pound = Ne = NeC = ECC - number_meter = kilometer / kilogram = Nm -@end - - -#### CGS ELECTROMAGNETIC UNITS #### - -# === Gaussian system of units === -@group Gaussian - franklin = erg ** 0.5 * centimeter ** 0.5 = Fr = statcoulomb = statC = esu - statvolt = erg / franklin = statV - statampere = franklin / second = statA - gauss = dyne / franklin = G - maxwell = gauss * centimeter ** 2 = Mx - oersted = dyne / maxwell = Oe = ørsted - statohm = statvolt / statampere = statΩ - statfarad = franklin / statvolt = statF - statmho = statampere / statvolt -@end -# Note this system is not commensurate with SI, as ε_0 and µ_0 disappear; -# some quantities with different dimensions in SI have the same -# dimensions in the Gaussian system (e.g. [Mx] = [Fr], but [Wb] != [C]), -# and therefore the conversion factors depend on the context (not in pint sense) -[gaussian_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] -[gaussian_current] = [gaussian_charge] / [time] -[gaussian_electric_potential] = [gaussian_charge] / [length] -[gaussian_electric_field] = [gaussian_electric_potential] / [length] -[gaussian_electric_displacement_field] = [gaussian_charge] / [area] -[gaussian_electric_flux] = [gaussian_charge] -[gaussian_electric_dipole] = [gaussian_charge] * [length] -[gaussian_electric_quadrupole] = [gaussian_charge] * [area] -[gaussian_magnetic_field] = [force] / [gaussian_charge] -[gaussian_magnetic_field_strength] = [gaussian_magnetic_field] -[gaussian_magnetic_flux] = [gaussian_magnetic_field] * [area] -[gaussian_magnetic_dipole] = [energy] / [gaussian_magnetic_field] -[gaussian_resistance] = [gaussian_electric_potential] / [gaussian_current] -[gaussian_resistivity] = [gaussian_resistance] * [length] -[gaussian_capacitance] = [gaussian_charge] / [gaussian_electric_potential] -[gaussian_inductance] = [gaussian_electric_potential] * [time] / [gaussian_current] -[gaussian_conductance] = [gaussian_current] / [gaussian_electric_potential] -@context Gaussian = Gau - [gaussian_charge] -> [charge]: value / k_C ** 0.5 - [charge] -> [gaussian_charge]: value * k_C ** 0.5 - [gaussian_current] -> [current]: value / k_C ** 0.5 - [current] -> [gaussian_current]: value * k_C ** 0.5 - [gaussian_electric_potential] -> [electric_potential]: value * k_C ** 0.5 - [electric_potential] -> [gaussian_electric_potential]: value / k_C ** 0.5 - [gaussian_electric_field] -> [electric_field]: value * k_C ** 0.5 - [electric_field] -> [gaussian_electric_field]: value / k_C ** 0.5 - [gaussian_electric_displacement_field] -> [electric_displacement_field]: value / (4 * π / ε_0) ** 0.5 - [electric_displacement_field] -> [gaussian_electric_displacement_field]: value * (4 * π / ε_0) ** 0.5 - [gaussian_electric_dipole] -> [electric_dipole]: value / k_C ** 0.5 - [electric_dipole] -> [gaussian_electric_dipole]: value * k_C ** 0.5 - [gaussian_electric_quadrupole] -> [electric_quadrupole]: value / k_C ** 0.5 - [electric_quadrupole] -> [gaussian_electric_quadrupole]: value * k_C ** 0.5 - [gaussian_magnetic_field] -> [magnetic_field]: value / (4 * π / µ_0) ** 0.5 - [magnetic_field] -> [gaussian_magnetic_field]: value * (4 * π / µ_0) ** 0.5 - [gaussian_magnetic_flux] -> [magnetic_flux]: value / (4 * π / µ_0) ** 0.5 - [magnetic_flux] -> [gaussian_magnetic_flux]: value * (4 * π / µ_0) ** 0.5 - [gaussian_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π * µ_0) ** 0.5 - [magnetic_field_strength] -> [gaussian_magnetic_field_strength]: value * (4 * π * µ_0) ** 0.5 - [gaussian_magnetic_dipole] -> [magnetic_dipole]: value * (4 * π / µ_0) ** 0.5 - [magnetic_dipole] -> [gaussian_magnetic_dipole]: value / (4 * π / µ_0) ** 0.5 - [gaussian_resistance] -> [resistance]: value * k_C - [resistance] -> [gaussian_resistance]: value / k_C - [gaussian_resistivity] -> [resistivity]: value * k_C - [resistivity] -> [gaussian_resistivity]: value / k_C - [gaussian_capacitance] -> [capacitance]: value / k_C - [capacitance] -> [gaussian_capacitance]: value * k_C - [gaussian_inductance] -> [inductance]: value * k_C - [inductance] -> [gaussian_inductance]: value / k_C - [gaussian_conductance] -> [conductance]: value / k_C - [conductance] -> [gaussian_conductance]: value * k_C -@end - -# === ESU system of units === -# (where different from Gaussian) -# See note for Gaussian system too -@group ESU using Gaussian - statweber = statvolt * second = statWb - stattesla = statweber / centimeter ** 2 = statT - stathenry = statweber / statampere = statH -@end -[esu_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] -[esu_current] = [esu_charge] / [time] -[esu_electric_potential] = [esu_charge] / [length] -[esu_magnetic_flux] = [esu_electric_potential] * [time] -[esu_magnetic_field] = [esu_magnetic_flux] / [area] -[esu_magnetic_field_strength] = [esu_current] / [length] -[esu_magnetic_dipole] = [esu_current] * [area] -@context ESU = esu - [esu_magnetic_field] -> [magnetic_field]: value * k_C ** 0.5 - [magnetic_field] -> [esu_magnetic_field]: value / k_C ** 0.5 - [esu_magnetic_flux] -> [magnetic_flux]: value * k_C ** 0.5 - [magnetic_flux] -> [esu_magnetic_flux]: value / k_C ** 0.5 - [esu_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π / ε_0) ** 0.5 - [magnetic_field_strength] -> [esu_magnetic_field_strength]: value * (4 * π / ε_0) ** 0.5 - [esu_magnetic_dipole] -> [magnetic_dipole]: value / k_C ** 0.5 - [magnetic_dipole] -> [esu_magnetic_dipole]: value * k_C ** 0.5 -@end - - -#### CONVERSION CONTEXTS #### - -@context(n=1) spectroscopy = sp - # n index of refraction of the medium. - [length] <-> [frequency]: speed_of_light / n / value - [frequency] -> [energy]: planck_constant * value - [energy] -> [frequency]: value / planck_constant - # allow wavenumber / kayser - [wavenumber] <-> [length]: 1 / value -@end - -@context boltzmann - [temperature] -> [energy]: boltzmann_constant * value - [energy] -> [temperature]: value / boltzmann_constant -@end - -@context energy - [energy] -> [energy] / [substance]: value * N_A - [energy] / [substance] -> [energy]: value / N_A - [energy] -> [mass]: value / c ** 2 - [mass] -> [energy]: value * c ** 2 -@end - -@context(mw=0,volume=0,solvent_mass=0) chemistry = chem - # mw is the molecular weight of the species - # volume is the volume of the solution - # solvent_mass is the mass of solvent in the solution - - # moles -> mass require the molecular weight - [substance] -> [mass]: value * mw - [mass] -> [substance]: value / mw - - # moles/volume -> mass/volume and moles/mass -> mass/mass - # require the molecular weight - [substance] / [volume] -> [mass] / [volume]: value * mw - [mass] / [volume] -> [substance] / [volume]: value / mw - [substance] / [mass] -> [mass] / [mass]: value * mw - [mass] / [mass] -> [substance] / [mass]: value / mw - - # moles/volume -> moles requires the solution volume - [substance] / [volume] -> [substance]: value * volume - [substance] -> [substance] / [volume]: value / volume - - # moles/mass -> moles requires the solvent (usually water) mass - [substance] / [mass] -> [substance]: value * solvent_mass - [substance] -> [substance] / [mass]: value / solvent_mass - - # moles/mass -> moles/volume require the solvent mass and the volume - [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume - [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume - -@end - -@context textile - # Allow switching between Direct count system (i.e. tex) and - # Indirect count system (i.e. Ne, Nm) - [mass] / [length] <-> [length] / [mass]: 1 / value -@end - - -#### SYSTEMS OF UNITS #### - -@system SI - second - meter - kilogram - ampere - kelvin - mole - candela -@end - -@system mks using international - meter - kilogram - second -@end - -@system cgs using international, Gaussian, ESU - centimeter - gram - second -@end - -@system atomic using international - # based on unit m_e, e, hbar, k_C, k - bohr: meter - electron_mass: gram - atomic_unit_of_time: second - atomic_unit_of_current: ampere - atomic_unit_of_temperature: kelvin -@end - -@system Planck using international - # based on unit c, gravitational_constant, hbar, k_C, k - planck_length: meter - planck_mass: gram - planck_time: second - planck_current: ampere - planck_temperature: kelvin -@end - -@system imperial using ImperialVolume, USCSLengthInternational, AvoirdupoisUK - yard - pound -@end - -@system US using USCSLiquidVolume, USCSDryVolume, USCSVolumeOther, USCSLengthInternational, USCSLengthSurvey, AvoirdupoisUS - yard - pound -@end - -pixel = 1 micrometer = px -xpixel = 1 micrometer = xpx -ypixel = 1 micrometer = ypx -zpixel = 1 micrometer = zpx -simulation_xpixel = 1 micrometer = sxpx -simulation_ypixel = 1 micrometer = sypx -simulation_zpixel = 1 micrometer = szpx - -""" \ No newline at end of file From 28b6b6bdfa52f7e5c6bb2555f68ac30a14455393 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 21:54:06 +0100 Subject: [PATCH 027/105] Create pint_definition.py --- deeptrack/backend/pint_definition.py | 943 +++++++++++++++++++++++++++ 1 file changed, 943 insertions(+) create mode 100644 deeptrack/backend/pint_definition.py diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py new file mode 100644 index 000000000..f8137bd07 --- /dev/null +++ b/deeptrack/backend/pint_definition.py @@ -0,0 +1,943 @@ +pint_constants = """ +# Default Pint constants definition file +# Based on the International System of Units +# Language: english +# Source: https://physics.nist.gov/cuu/Constants/ +# https://physics.nist.gov/PhysRefData/XrayTrans/Html/search.html +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +#### MATHEMATICAL CONSTANTS #### +# As computed by Maxima with fpprec:50 + +pi = 3.1415926535897932384626433832795028841971693993751 = π # pi +tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian +ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 +wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 +wien_u = 2.8214393721220788934031913302944851953458817440731 # solution to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3 +eulers_number = 2.71828182845904523536028747135266249775724709369995 + +#### DEFINED EXACT CONSTANTS #### + +speed_of_light = 299792458 m/s = c = c_0 # since 1983 +planck_constant = 6.62607015e-34 J s = h # since May 2019 +elementary_charge = 1.602176634e-19 C = e # since May 2019 +avogadro_number = 6.02214076e23 # since May 2019 +boltzmann_constant = 1.380649e-23 J K^-1 = k = k_B # since May 2019 +standard_gravity = 9.80665 m/s^2 = g_0 = g0 = g_n = gravity # since 1901 +standard_atmosphere = 1.01325e5 Pa = atm = atmosphere # since 1954 +conventional_josephson_constant = 4.835979e14 Hz / V = K_J90 # since Jan 1990 +conventional_von_klitzing_constant = 2.5812807e4 ohm = R_K90 # since Jan 1990 + +#### DERIVED EXACT CONSTANTS #### +# Floating-point conversion may introduce inaccuracies + +zeta = c / (cm/s) = ζ +dirac_constant = h / (2 * π) = ħ = hbar = atomic_unit_of_action = a_u_action +avogadro_constant = avogadro_number * mol^-1 = N_A +molar_gas_constant = k * N_A = R +faraday_constant = e * N_A +conductance_quantum = 2 * e ** 2 / h = G_0 +magnetic_flux_quantum = h / (2 * e) = Φ_0 = Phi_0 +josephson_constant = 2 * e / h = K_J +von_klitzing_constant = h / e ** 2 = R_K +stefan_boltzmann_constant = 2 / 15 * π ** 5 * k ** 4 / (h ** 3 * c ** 2) = σ = sigma +first_radiation_constant = 2 * π * h * c ** 2 = c_1 +second_radiation_constant = h * c / k = c_2 +wien_wavelength_displacement_law_constant = h * c / (k * wien_x) +wien_frequency_displacement_law_constant = wien_u * k / h + +#### MEASURED CONSTANTS #### +# Recommended CODATA-2018 values +# To some extent, what is measured and what is derived is a bit arbitrary. +# The choice of measured constants is based on convenience and on available uncertainty. +# The uncertainty in the last significant digits is given in parentheses as a comment. + +newtonian_constant_of_gravitation = 6.67430e-11 m^3/(kg s^2) = _ = gravitational_constant # (15) +rydberg_constant = 1.0973731568160e7 * m^-1 = R_∞ = R_inf # (21) +electron_g_factor = -2.00231930436256 = g_e # (35) +atomic_mass_constant = 1.66053906660e-27 kg = m_u # (50) +electron_mass = 9.1093837015e-31 kg = m_e = atomic_unit_of_mass = a_u_mass # (28) +proton_mass = 1.67262192369e-27 kg = m_p # (51) +neutron_mass = 1.67492749804e-27 kg = m_n # (95) +lattice_spacing_of_Si = 1.920155716e-10 m = d_220 # (32) +K_alpha_Cu_d_220 = 0.80232719 # (22) +K_alpha_Mo_d_220 = 0.36940604 # (19) +K_alpha_W_d_220 = 0.108852175 # (98) + +#### DERIVED CONSTANTS #### + +fine_structure_constant = (2 * h * R_inf / (m_e * c)) ** 0.5 = α = alpha +vacuum_permeability = 2 * α * h / (e ** 2 * c) = µ_0 = mu_0 = mu0 = magnetic_constant +vacuum_permittivity = e ** 2 / (2 * α * h * c) = ε_0 = epsilon_0 = eps_0 = eps0 = electric_constant +impedance_of_free_space = 2 * α * h / e ** 2 = Z_0 = characteristic_impedance_of_vacuum +coulomb_constant = α * hbar * c / e ** 2 = k_C +classical_electron_radius = α * hbar / (m_e * c) = r_e +thomson_cross_section = 8 / 3 * π * r_e ** 2 = σ_e = sigma_e +""" + +pint_definitions = f""" +# Default Pint units definition file +# Based on the International System of Units +# Language: english +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +# Syntax +# ====== +# Units +# ----- +# = [= ] [= ] [ = ] [...] +# +# The canonical name and aliases should be expressed in singular form. +# Pint automatically deals with plurals built by adding 's' to the singular form; plural +# forms that don't follow this rule should be instead explicitly listed as aliases. +# +# If a unit has no symbol and one wants to define aliases, then the symbol should be +# conventionally set to _. +# +# Example: +# millennium = 1e3 * year = _ = millennia +# +# +# Prefixes +# -------- +# - = [= ] [= ] [ = ] [...] +# +# Example: +# deca- = 1e+1 = da- = deka- +# +# +# Derived dimensions +# ------------------ +# [dimension name] = +# +# Example: +# [density] = [mass] / [volume] +# +# Note that primary dimensions don't need to be declared; they can be +# defined for the first time in a unit definition. +# E.g. see below `meter = [length]` +# +# +# Additional aliases +# ------------------ +# @alias = [ = ] [...] +# +# Used to add aliases to already existing unit definitions. +# Particularly useful when one wants to enrich definitions +# from defaults_en.txt with custom aliases. +# +# Example: +# @alias meter = my_meter + +# See also: https://pint.readthedocs.io/en/latest/defining.html + +@defaults + group = international + system = mks +@end + + +#### PREFIXES #### + +# decimal prefixes +yocto- = 1e-24 = y- +zepto- = 1e-21 = z- +atto- = 1e-18 = a- +femto- = 1e-15 = f- +pico- = 1e-12 = p- +nano- = 1e-9 = n- +micro- = 1e-6 = µ- = u- +milli- = 1e-3 = m- +centi- = 1e-2 = c- +deci- = 1e-1 = d- +deca- = 1e+1 = da- = deka- +hecto- = 1e2 = h- +kilo- = 1e3 = k- +mega- = 1e6 = M- +giga- = 1e9 = G- +tera- = 1e12 = T- +peta- = 1e15 = P- +exa- = 1e18 = E- +zetta- = 1e21 = Z- +yotta- = 1e24 = Y- + +# binary_prefixes +kibi- = 2**10 = Ki- +mebi- = 2**20 = Mi- +gibi- = 2**30 = Gi- +tebi- = 2**40 = Ti- +pebi- = 2**50 = Pi- +exbi- = 2**60 = Ei- +zebi- = 2**70 = Zi- +yobi- = 2**80 = Yi- + +# extra_prefixes +semi- = 0.5 = _ = demi- +sesqui- = 1.5 + + +#### BASE UNITS #### + +meter = [length] = m = metre +second = [time] = s = sec +ampere = [current] = A = amp +candela = [luminosity] = cd = candle +gram = [mass] = g +mole = [substance] = mol +kelvin = [temperature]; offset: 0 = K = degK = °K = degree_Kelvin = degreeK # older names supported for compatibility +radian = [] = rad +bit = [] +count = [] + + +#### CONSTANTS #### + +{pint_constants} + + +#### UNITS #### +# Common and less common, grouped by quantity. +# Conversion factors are exact (except when noted), +# although floating-point conversion may introduce inaccuracies + +# Angle +turn = 2 * π * radian = _ = revolution = cycle = circle +degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree +arcminute = degree / 60 = arcmin = arc_minute = angular_minute +arcsecond = arcminute / 60 = arcsec = arc_second = angular_second +milliarcsecond = 1e-3 * arcsecond = mas +grade = π / 200 * radian = grad = gon +mil = π / 32000 * radian + +# Solid angle +steradian = radian ** 2 = sr +square_degree = (π / 180) ** 2 * sr = sq_deg = sqdeg + +# Information +baud = bit / second = Bd = bps + +byte = 8 * bit = B = octet +# byte = 8 * bit = _ = octet +## NOTE: B (byte) symbol can conflict with Bell + +# Length +angstrom = 1e-10 * meter = Å = ångström = Å +micron = micrometer = µ +fermi = femtometer = fm +light_year = speed_of_light * julian_year = ly = lightyear +astronomical_unit = 149597870700 * meter = au # since Aug 2012 +parsec = 1 / tansec * astronomical_unit = pc +nautical_mile = 1852 * meter = nmi +bohr = hbar / (alpha * m_e * c) = a_0 = a0 = bohr_radius = atomic_unit_of_length = a_u_length +x_unit_Cu = K_alpha_Cu_d_220 * d_220 / 1537.4 = Xu_Cu +x_unit_Mo = K_alpha_Mo_d_220 * d_220 / 707.831 = Xu_Mo +angstrom_star = K_alpha_W_d_220 * d_220 / 0.2090100 = Å_star +planck_length = (hbar * gravitational_constant / c ** 3) ** 0.5 + +# Mass +metric_ton = 1e3 * kilogram = t = tonne +unified_atomic_mass_unit = atomic_mass_constant = u = amu +dalton = atomic_mass_constant = Da +grain = 64.79891 * milligram = gr +gamma_mass = microgram +carat = 200 * milligram = ct = karat +planck_mass = (hbar * c / gravitational_constant) ** 0.5 + +# Time +minute = 60 * second = min +hour = 60 * minute = hr +day = 24 * hour = d +week = 7 * day +fortnight = 2 * week +year = 365.25 * day = a = yr = julian_year +month = year / 12 + +# decade = 10 * year +## NOTE: decade [time] can conflict with decade [dimensionless] + +century = 100 * year = _ = centuries +millennium = 1e3 * year = _ = millennia +eon = 1e9 * year +shake = 1e-8 * second +svedberg = 1e-13 * second +atomic_unit_of_time = hbar / E_h = a_u_time +gregorian_year = 365.2425 * day +sidereal_year = 365.256363004 * day # approximate, as of J2000 epoch +tropical_year = 365.242190402 * day # approximate, as of J2000 epoch +common_year = 365 * day +leap_year = 366 * day +sidereal_day = day / 1.00273790935079524 # approximate +sidereal_month = 27.32166155 * day # approximate +tropical_month = 27.321582 * day # approximate +synodic_month = 29.530589 * day = _ = lunar_month # approximate +planck_time = (hbar * gravitational_constant / c ** 5) ** 0.5 + +# Temperature +degree_Celsius = kelvin; offset: 273.15 = °C = celsius = degC = degreeC +degree_Rankine = 5 / 9 * kelvin; offset: 0 = °R = rankine = degR = degreeR +degree_Fahrenheit = 5 / 9 * kelvin; offset: 233.15 + 200 / 9 = °F = fahrenheit = degF = degreeF +degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degreeRe = degree_Réaumur = réaumur +atomic_unit_of_temperature = E_h / k = a_u_temp +planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5 + +# Area +[area] = [length] ** 2 +are = 100 * meter ** 2 +barn = 1e-28 * meter ** 2 = b +darcy = centipoise * centimeter ** 2 / (second * atmosphere) +hectare = 100 * are = ha + +# Volume +[volume] = [length] ** 3 +liter = decimeter ** 3 = l = L = litre +cubic_centimeter = centimeter ** 3 = cc +lambda = microliter = λ +stere = meter ** 3 + +# Frequency +[frequency] = 1 / [time] +hertz = 1 / second = Hz +revolutions_per_minute = revolution / minute = rpm +revolutions_per_second = revolution / second = rps +counts_per_second = count / second = cps + +# Wavenumber +[wavenumber] = 1 / [length] +reciprocal_centimeter = 1 / cm = cm_1 = kayser + +# Velocity +[velocity] = [length] / [time] +[speed] = [velocity] +knot = nautical_mile / hour = kt = knot_international = international_knot +mile_per_hour = mile / hour = mph = MPH +kilometer_per_hour = kilometer / hour = kph = KPH +kilometer_per_second = kilometer / second = kps +meter_per_second = meter / second = mps +foot_per_second = foot / second = fps + +# Acceleration +[acceleration] = [velocity] / [time] +galileo = centimeter / second ** 2 = Gal + +# Force +[force] = [mass] * [acceleration] +newton = kilogram * meter / second ** 2 = N +dyne = gram * centimeter / second ** 2 = dyn +force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond +force_gram = g_0 * gram = gf = gram_force +force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force +atomic_unit_of_force = E_h / a_0 = a_u_force + +# Energy +[energy] = [force] * [length] +joule = newton * meter = J +erg = dyne * centimeter +watt_hour = watt * hour = Wh = watthour +electron_volt = e * volt = eV +rydberg = h * c * R_inf = Ry +hartree = 2 * rydberg = E_h = Eh = hartree_energy = atomic_unit_of_energy = a_u_energy +calorie = 4.184 * joule = cal = thermochemical_calorie = cal_th +international_calorie = 4.1868 * joule = cal_it = international_steam_table_calorie +fifteen_degree_calorie = 4.1855 * joule = cal_15 +british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso +international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it +thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th +quadrillion_Btu = 1e15 * Btu = quad +therm = 1e5 * Btu = thm = EC_therm +US_therm = 1.054804e8 * joule # approximate, no exact definition +ton_TNT = 1e9 * calorie = tTNT +tonne_of_oil_equivalent = 1e10 * international_calorie = toe +atmosphere_liter = atmosphere * liter = atm_l + +# Power +[power] = [energy] / [time] +watt = joule / second = W +volt_ampere = volt * ampere = VA +horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower +boiler_horsepower = 33475 * Btu / hour # unclear which Btu +metric_horsepower = 75 * force_kilogram * meter / second +electrical_horsepower = 746 * watt +refrigeration_ton = 12e3 * Btu / hour = _ = ton_of_refrigeration # approximate, no exact definition +standard_liter_per_minute = atmosphere * liter / minute = slpm = slm +conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90 + +# Momentum +[momentum] = [length] * [mass] / [time] + +# Density (as auxiliary for pressure) +[density] = [mass] / [volume] +mercury = 13.5951 * kilogram / liter = Hg = Hg_0C = Hg_32F = conventional_mercury +water = 1.0 * kilogram / liter = H2O = conventional_water +mercury_60F = 13.5568 * kilogram / liter = Hg_60F # approximate +water_39F = 0.999972 * kilogram / liter = water_4C # approximate +water_60F = 0.999001 * kilogram / liter # approximate + +# Pressure +[pressure] = [force] / [area] +pascal = newton / meter ** 2 = Pa +barye = dyne / centimeter ** 2 = Ba = barie = barad = barrie = baryd +bar = 1e5 * pascal +technical_atmosphere = kilogram * g_0 / centimeter ** 2 = at +torr = atm / 760 +pound_force_per_square_inch = force_pound / inch ** 2 = psi +kip_per_square_inch = kip / inch ** 2 = ksi +millimeter_Hg = millimeter * Hg * g_0 = mmHg = mm_Hg = millimeter_Hg_0C +centimeter_Hg = centimeter * Hg * g_0 = cmHg = cm_Hg = centimeter_Hg_0C +inch_Hg = inch * Hg * g_0 = inHg = in_Hg = inch_Hg_32F +inch_Hg_60F = inch * Hg_60F * g_0 +inch_H2O_39F = inch * water_39F * g_0 +inch_H2O_60F = inch * water_60F * g_0 +foot_H2O = foot * water * g_0 = ftH2O = feet_H2O +centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O +sound_pressure_level = 20e-6 * pascal = SPL + +# Torque +[torque] = [force] * [length] +foot_pound = foot * force_pound = ft_lb = footpound + +# Viscosity +[viscosity] = [pressure] * [time] +poise = 0.1 * Pa * second = P +reyn = psi * second + +# Kinematic viscosity +[kinematic_viscosity] = [area] / [time] +stokes = centimeter ** 2 / second = St + +# Fluidity +[fluidity] = 1 / [viscosity] +rhe = 1 / poise + +# Amount of substance +particle = 1 / N_A = _ = molec = molecule + +# Concentration +[concentration] = [substance] / [volume] +molar = mole / liter = M + +# Catalytic activity +[activity] = [substance] / [time] +katal = mole / second = kat +enzyme_unit = micromole / minute = U = enzymeunit + +# Entropy +[entropy] = [energy] / [temperature] +clausius = calorie / kelvin = Cl + +# Molar entropy +[molar_entropy] = [entropy] / [substance] +entropy_unit = calorie / kelvin / mole = eu + +# Radiation +becquerel = counts_per_second = Bq +curie = 3.7e10 * becquerel = Ci +rutherford = 1e6 * becquerel = Rd +gray = joule / kilogram = Gy +sievert = joule / kilogram = Sv +rads = 0.01 * gray +rem = 0.01 * sievert +roentgen = 2.58e-4 * coulomb / kilogram = _ = röntgen # approximate, depends on medium + +# Heat transimission +[heat_transmission] = [energy] / [area] +peak_sun_hour = 1e3 * watt_hour / meter ** 2 = PSH +langley = thermochemical_calorie / centimeter ** 2 = Ly + +# Luminance +[luminance] = [luminosity] / [area] +nit = candela / meter ** 2 +stilb = candela / centimeter ** 2 +lambert = 1 / π * candela / centimeter ** 2 + +# Luminous flux +[luminous_flux] = [luminosity] +lumen = candela * steradian = lm + +# Illuminance +[illuminance] = [luminous_flux] / [area] +lux = lumen / meter ** 2 = lx + +# Intensity +[intensity] = [power] / [area] +atomic_unit_of_intensity = 0.5 * ε_0 * c * atomic_unit_of_electric_field ** 2 = a_u_intensity + +# Current +biot = 10 * ampere = Bi +abampere = biot = abA +atomic_unit_of_current = e / atomic_unit_of_time = a_u_current +mean_international_ampere = mean_international_volt / mean_international_ohm = A_it +US_international_ampere = US_international_volt / US_international_ohm = A_US +conventional_ampere_90 = K_J90 * R_K90 / (K_J * R_K) * ampere = A_90 +planck_current = (c ** 6 / gravitational_constant / k_C) ** 0.5 + +# Charge +[charge] = [current] * [time] +coulomb = ampere * second = C +abcoulomb = 10 * C = abC +faraday = e * N_A * mole +conventional_coulomb_90 = K_J90 * R_K90 / (K_J * R_K) * coulomb = C_90 +ampere_hour = ampere * hour = Ah + +# Electric potential +[electric_potential] = [energy] / [charge] +volt = joule / coulomb = V +abvolt = 1e-8 * volt = abV +mean_international_volt = 1.00034 * volt = V_it # approximate +US_international_volt = 1.00033 * volt = V_US # approximate +conventional_volt_90 = K_J90 / K_J * volt = V_90 + +# Electric field +[electric_field] = [electric_potential] / [length] +atomic_unit_of_electric_field = e * k_C / a_0 ** 2 = a_u_electric_field + +# Electric displacement field +[electric_displacement_field] = [charge] / [area] + +# Resistance +[resistance] = [electric_potential] / [current] +ohm = volt / ampere = Ω +abohm = 1e-9 * ohm = abΩ +mean_international_ohm = 1.00049 * ohm = Ω_it = ohm_it # approximate +US_international_ohm = 1.000495 * ohm = Ω_US = ohm_US # approximate +conventional_ohm_90 = R_K / R_K90 * ohm = Ω_90 = ohm_90 + +# Resistivity +[resistivity] = [resistance] * [length] + +# Conductance +[conductance] = [current] / [electric_potential] +siemens = ampere / volt = S = mho +absiemens = 1e9 * siemens = abS = abmho + +# Capacitance +[capacitance] = [charge] / [electric_potential] +farad = coulomb / volt = F +abfarad = 1e9 * farad = abF +conventional_farad_90 = R_K90 / R_K * farad = F_90 + +# Inductance +[inductance] = [magnetic_flux] / [current] +henry = weber / ampere = H +abhenry = 1e-9 * henry = abH +conventional_henry_90 = R_K / R_K90 * henry = H_90 + +# Magnetic flux +[magnetic_flux] = [electric_potential] * [time] +weber = volt * second = Wb +unit_pole = µ_0 * biot * centimeter + +# Magnetic field +[magnetic_field] = [magnetic_flux] / [area] +tesla = weber / meter ** 2 = T +gamma = 1e-9 * tesla = γ + +# Magnetomotive force +[magnetomotive_force] = [current] +ampere_turn = ampere = At +biot_turn = biot +gilbert = 1 / (4 * π) * biot_turn = Gb + +# Magnetic field strength +[magnetic_field_strength] = [current] / [length] + +# Electric dipole moment +[electric_dipole] = [charge] * [length] +debye = 1e-9 / ζ * coulomb * angstrom = D # formally 1 D = 1e-10 Fr*Å, but we generally want to use it outside the Gaussian context + +# Electric quadrupole moment +[electric_quadrupole] = [charge] * [area] +buckingham = debye * angstrom + +# Magnetic dipole moment +[magnetic_dipole] = [current] * [area] +bohr_magneton = e * hbar / (2 * m_e) = µ_B = mu_B +nuclear_magneton = e * hbar / (2 * m_p) = µ_N = mu_N + +# Logaritmic Unit Definition +# Unit = scale; logbase; logfactor +# x_dB = [logfactor] * log( x_lin / [scale] ) / log( [logbase] ) + +# Logaritmic Units of dimensionless quantity: [ https://en.wikipedia.org/wiki/Level_(logarithmic_quantity) ] + +decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm +decibelmicrowatt = 1e-6 watt; logbase: 10; logfactor: 10 = dBu + +decibel = 1 ; logbase: 10; logfactor: 10 = dB +# bell = 1 ; logbase: 10; logfactor: = B +## NOTE: B (Bell) symbol conflicts with byte + +decade = 1 ; logbase: 10; logfactor: 1 +## NOTE: decade [time] can conflict with decade [dimensionless] + +octave = 1 ; logbase: 2; logfactor: 1 = oct + +neper = 1 ; logbase: 2.71828182845904523536028747135266249775724709369995; logfactor: 0.5 = Np +# neper = 1 ; logbase: eulers_number; logfactor: 0.5 = Np + +#### UNIT GROUPS #### +# Mostly for length, area, volume, mass, force +# (customary or specialized units) + +@group USCSLengthInternational + thou = 1e-3 * inch = th = mil_length + inch = yard / 36 = in = international_inch = inches = international_inches + hand = 4 * inch + foot = yard / 3 = ft = international_foot = feet = international_feet + yard = 0.9144 * meter = yd = international_yard # since Jul 1959 + mile = 1760 * yard = mi = international_mile + + circular_mil = π / 4 * mil_length ** 2 = cmil + square_inch = inch ** 2 = sq_in = square_inches + square_foot = foot ** 2 = sq_ft = square_feet + square_yard = yard ** 2 = sq_yd + square_mile = mile ** 2 = sq_mi + + cubic_inch = in ** 3 = cu_in + cubic_foot = ft ** 3 = cu_ft = cubic_feet + cubic_yard = yd ** 3 = cu_yd +@end + +@group USCSLengthSurvey + link = 1e-2 * chain = li = survey_link + survey_foot = 1200 / 3937 * meter = sft + fathom = 6 * survey_foot + rod = 16.5 * survey_foot = rd = pole = perch + chain = 4 * rod + furlong = 40 * rod = fur + cables_length = 120 * fathom + survey_mile = 5280 * survey_foot = smi = us_statute_mile + league = 3 * survey_mile + + square_rod = rod ** 2 = sq_rod = sq_pole = sq_perch + acre = 10 * chain ** 2 + square_survey_mile = survey_mile ** 2 = _ = section + square_league = league ** 2 + + acre_foot = acre * survey_foot = _ = acre_feet +@end + +@group USCSDryVolume + dry_pint = bushel / 64 = dpi = US_dry_pint + dry_quart = bushel / 32 = dqt = US_dry_quart + dry_gallon = bushel / 8 = dgal = US_dry_gallon + peck = bushel / 4 = pk + bushel = 2150.42 cubic_inch = bu + dry_barrel = 7056 cubic_inch = _ = US_dry_barrel + board_foot = ft * ft * in = FBM = board_feet = BF = BDFT = super_foot = superficial_foot = super_feet = superficial_feet +@end + +@group USCSLiquidVolume + minim = pint / 7680 + fluid_dram = pint / 128 = fldr = fluidram = US_fluid_dram = US_liquid_dram + fluid_ounce = pint / 16 = floz = US_fluid_ounce = US_liquid_ounce + gill = pint / 4 = gi = liquid_gill = US_liquid_gill + pint = quart / 2 = pt = liquid_pint = US_pint + fifth = gallon / 5 = _ = US_liquid_fifth + quart = gallon / 4 = qt = liquid_quart = US_liquid_quart + gallon = 231 * cubic_inch = gal = liquid_gallon = US_liquid_gallon +@end + +@group USCSVolumeOther + teaspoon = fluid_ounce / 6 = tsp + tablespoon = fluid_ounce / 2 = tbsp + shot = 3 * tablespoon = jig = US_shot + cup = pint / 2 = cp = liquid_cup = US_liquid_cup + barrel = 31.5 * gallon = bbl + oil_barrel = 42 * gallon = oil_bbl + beer_barrel = 31 * gallon = beer_bbl + hogshead = 63 * gallon +@end + +@group Avoirdupois + dram = pound / 256 = dr = avoirdupois_dram = avdp_dram = drachm + ounce = pound / 16 = oz = avoirdupois_ounce = avdp_ounce + pound = 7e3 * grain = lb = avoirdupois_pound = avdp_pound + stone = 14 * pound + quarter = 28 * stone + bag = 94 * pound + hundredweight = 100 * pound = cwt = short_hundredweight + long_hundredweight = 112 * pound + ton = 2e3 * pound = _ = short_ton + long_ton = 2240 * pound + slug = g_0 * pound * second ** 2 / foot + slinch = g_0 * pound * second ** 2 / inch = blob = slugette + + force_ounce = g_0 * ounce = ozf = ounce_force + force_pound = g_0 * pound = lbf = pound_force + force_ton = g_0 * ton = _ = ton_force = force_short_ton = short_ton_force + force_long_ton = g_0 * long_ton = _ = long_ton_force + kip = 1e3 * force_pound + poundal = pound * foot / second ** 2 = pdl +@end + +@group AvoirdupoisUK using Avoirdupois + UK_hundredweight = long_hundredweight = UK_cwt + UK_ton = long_ton + UK_force_ton = force_long_ton = _ = UK_ton_force +@end + +@group AvoirdupoisUS using Avoirdupois + US_hundredweight = hundredweight = US_cwt + US_ton = ton + US_force_ton = force_ton = _ = US_ton_force +@end + +@group Troy + pennyweight = 24 * grain = dwt + troy_ounce = 480 * grain = toz = ozt + troy_pound = 12 * troy_ounce = tlb = lbt +@end + +@group Apothecary + scruple = 20 * grain + apothecary_dram = 3 * scruple = ap_dr + apothecary_ounce = 8 * apothecary_dram = ap_oz + apothecary_pound = 12 * apothecary_ounce = ap_lb +@end + +@group ImperialVolume + imperial_minim = imperial_fluid_ounce / 480 + imperial_fluid_scruple = imperial_fluid_ounce / 24 + imperial_fluid_drachm = imperial_fluid_ounce / 8 = imperial_fldr = imperial_fluid_dram + imperial_fluid_ounce = imperial_pint / 20 = imperial_floz = UK_fluid_ounce + imperial_gill = imperial_pint / 4 = imperial_gi = UK_gill + imperial_cup = imperial_pint / 2 = imperial_cp = UK_cup + imperial_pint = imperial_gallon / 8 = imperial_pt = UK_pint + imperial_quart = imperial_gallon / 4 = imperial_qt = UK_quart + imperial_gallon = 4.54609 * liter = imperial_gal = UK_gallon + imperial_peck = 2 * imperial_gallon = imperial_pk = UK_pk + imperial_bushel = 8 * imperial_gallon = imperial_bu = UK_bushel + imperial_barrel = 36 * imperial_gallon = imperial_bbl = UK_bbl +@end + +@group Textile + tex = gram / kilometer = Tt + dtex = decitex + denier = gram / (9 * kilometer) = den = Td + jute = pound / (14400 * yard) = Tj + aberdeen = jute = Ta + RKM = gf / tex + + number_english = 840 * yard / pound = Ne = NeC = ECC + number_meter = kilometer / kilogram = Nm +@end + + +#### CGS ELECTROMAGNETIC UNITS #### + +# === Gaussian system of units === +@group Gaussian + franklin = erg ** 0.5 * centimeter ** 0.5 = Fr = statcoulomb = statC = esu + statvolt = erg / franklin = statV + statampere = franklin / second = statA + gauss = dyne / franklin = G + maxwell = gauss * centimeter ** 2 = Mx + oersted = dyne / maxwell = Oe = ørsted + statohm = statvolt / statampere = statΩ + statfarad = franklin / statvolt = statF + statmho = statampere / statvolt +@end +# Note this system is not commensurate with SI, as ε_0 and µ_0 disappear; +# some quantities with different dimensions in SI have the same +# dimensions in the Gaussian system (e.g. [Mx] = [Fr], but [Wb] != [C]), +# and therefore the conversion factors depend on the context (not in pint sense) +[gaussian_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[gaussian_current] = [gaussian_charge] / [time] +[gaussian_electric_potential] = [gaussian_charge] / [length] +[gaussian_electric_field] = [gaussian_electric_potential] / [length] +[gaussian_electric_displacement_field] = [gaussian_charge] / [area] +[gaussian_electric_flux] = [gaussian_charge] +[gaussian_electric_dipole] = [gaussian_charge] * [length] +[gaussian_electric_quadrupole] = [gaussian_charge] * [area] +[gaussian_magnetic_field] = [force] / [gaussian_charge] +[gaussian_magnetic_field_strength] = [gaussian_magnetic_field] +[gaussian_magnetic_flux] = [gaussian_magnetic_field] * [area] +[gaussian_magnetic_dipole] = [energy] / [gaussian_magnetic_field] +[gaussian_resistance] = [gaussian_electric_potential] / [gaussian_current] +[gaussian_resistivity] = [gaussian_resistance] * [length] +[gaussian_capacitance] = [gaussian_charge] / [gaussian_electric_potential] +[gaussian_inductance] = [gaussian_electric_potential] * [time] / [gaussian_current] +[gaussian_conductance] = [gaussian_current] / [gaussian_electric_potential] +@context Gaussian = Gau + [gaussian_charge] -> [charge]: value / k_C ** 0.5 + [charge] -> [gaussian_charge]: value * k_C ** 0.5 + [gaussian_current] -> [current]: value / k_C ** 0.5 + [current] -> [gaussian_current]: value * k_C ** 0.5 + [gaussian_electric_potential] -> [electric_potential]: value * k_C ** 0.5 + [electric_potential] -> [gaussian_electric_potential]: value / k_C ** 0.5 + [gaussian_electric_field] -> [electric_field]: value * k_C ** 0.5 + [electric_field] -> [gaussian_electric_field]: value / k_C ** 0.5 + [gaussian_electric_displacement_field] -> [electric_displacement_field]: value / (4 * π / ε_0) ** 0.5 + [electric_displacement_field] -> [gaussian_electric_displacement_field]: value * (4 * π / ε_0) ** 0.5 + [gaussian_electric_dipole] -> [electric_dipole]: value / k_C ** 0.5 + [electric_dipole] -> [gaussian_electric_dipole]: value * k_C ** 0.5 + [gaussian_electric_quadrupole] -> [electric_quadrupole]: value / k_C ** 0.5 + [electric_quadrupole] -> [gaussian_electric_quadrupole]: value * k_C ** 0.5 + [gaussian_magnetic_field] -> [magnetic_field]: value / (4 * π / µ_0) ** 0.5 + [magnetic_field] -> [gaussian_magnetic_field]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_flux] -> [magnetic_flux]: value / (4 * π / µ_0) ** 0.5 + [magnetic_flux] -> [gaussian_magnetic_flux]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π * µ_0) ** 0.5 + [magnetic_field_strength] -> [gaussian_magnetic_field_strength]: value * (4 * π * µ_0) ** 0.5 + [gaussian_magnetic_dipole] -> [magnetic_dipole]: value * (4 * π / µ_0) ** 0.5 + [magnetic_dipole] -> [gaussian_magnetic_dipole]: value / (4 * π / µ_0) ** 0.5 + [gaussian_resistance] -> [resistance]: value * k_C + [resistance] -> [gaussian_resistance]: value / k_C + [gaussian_resistivity] -> [resistivity]: value * k_C + [resistivity] -> [gaussian_resistivity]: value / k_C + [gaussian_capacitance] -> [capacitance]: value / k_C + [capacitance] -> [gaussian_capacitance]: value * k_C + [gaussian_inductance] -> [inductance]: value * k_C + [inductance] -> [gaussian_inductance]: value / k_C + [gaussian_conductance] -> [conductance]: value / k_C + [conductance] -> [gaussian_conductance]: value * k_C +@end + +# === ESU system of units === +# (where different from Gaussian) +# See note for Gaussian system too +@group ESU using Gaussian + statweber = statvolt * second = statWb + stattesla = statweber / centimeter ** 2 = statT + stathenry = statweber / statampere = statH +@end +[esu_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[esu_current] = [esu_charge] / [time] +[esu_electric_potential] = [esu_charge] / [length] +[esu_magnetic_flux] = [esu_electric_potential] * [time] +[esu_magnetic_field] = [esu_magnetic_flux] / [area] +[esu_magnetic_field_strength] = [esu_current] / [length] +[esu_magnetic_dipole] = [esu_current] * [area] +@context ESU = esu + [esu_magnetic_field] -> [magnetic_field]: value * k_C ** 0.5 + [magnetic_field] -> [esu_magnetic_field]: value / k_C ** 0.5 + [esu_magnetic_flux] -> [magnetic_flux]: value * k_C ** 0.5 + [magnetic_flux] -> [esu_magnetic_flux]: value / k_C ** 0.5 + [esu_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π / ε_0) ** 0.5 + [magnetic_field_strength] -> [esu_magnetic_field_strength]: value * (4 * π / ε_0) ** 0.5 + [esu_magnetic_dipole] -> [magnetic_dipole]: value / k_C ** 0.5 + [magnetic_dipole] -> [esu_magnetic_dipole]: value * k_C ** 0.5 +@end + + +#### CONVERSION CONTEXTS #### + +@context(n=1) spectroscopy = sp + # n index of refraction of the medium. + [length] <-> [frequency]: speed_of_light / n / value + [frequency] -> [energy]: planck_constant * value + [energy] -> [frequency]: value / planck_constant + # allow wavenumber / kayser + [wavenumber] <-> [length]: 1 / value +@end + +@context boltzmann + [temperature] -> [energy]: boltzmann_constant * value + [energy] -> [temperature]: value / boltzmann_constant +@end + +@context energy + [energy] -> [energy] / [substance]: value * N_A + [energy] / [substance] -> [energy]: value / N_A + [energy] -> [mass]: value / c ** 2 + [mass] -> [energy]: value * c ** 2 +@end + +@context(mw=0,volume=0,solvent_mass=0) chemistry = chem + # mw is the molecular weight of the species + # volume is the volume of the solution + # solvent_mass is the mass of solvent in the solution + + # moles -> mass require the molecular weight + [substance] -> [mass]: value * mw + [mass] -> [substance]: value / mw + + # moles/volume -> mass/volume and moles/mass -> mass/mass + # require the molecular weight + [substance] / [volume] -> [mass] / [volume]: value * mw + [mass] / [volume] -> [substance] / [volume]: value / mw + [substance] / [mass] -> [mass] / [mass]: value * mw + [mass] / [mass] -> [substance] / [mass]: value / mw + + # moles/volume -> moles requires the solution volume + [substance] / [volume] -> [substance]: value * volume + [substance] -> [substance] / [volume]: value / volume + + # moles/mass -> moles requires the solvent (usually water) mass + [substance] / [mass] -> [substance]: value * solvent_mass + [substance] -> [substance] / [mass]: value / solvent_mass + + # moles/mass -> moles/volume require the solvent mass and the volume + [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume + [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume + +@end + +@context textile + # Allow switching between Direct count system (i.e. tex) and + # Indirect count system (i.e. Ne, Nm) + [mass] / [length] <-> [length] / [mass]: 1 / value +@end + + +#### SYSTEMS OF UNITS #### + +@system SI + second + meter + kilogram + ampere + kelvin + mole + candela +@end + +@system mks using international + meter + kilogram + second +@end + +@system cgs using international, Gaussian, ESU + centimeter + gram + second +@end + +@system atomic using international + # based on unit m_e, e, hbar, k_C, k + bohr: meter + electron_mass: gram + atomic_unit_of_time: second + atomic_unit_of_current: ampere + atomic_unit_of_temperature: kelvin +@end + +@system Planck using international + # based on unit c, gravitational_constant, hbar, k_C, k + planck_length: meter + planck_mass: gram + planck_time: second + planck_current: ampere + planck_temperature: kelvin +@end + +@system imperial using ImperialVolume, USCSLengthInternational, AvoirdupoisUK + yard + pound +@end + +@system US using USCSLiquidVolume, USCSDryVolume, USCSVolumeOther, USCSLengthInternational, USCSLengthSurvey, AvoirdupoisUS + yard + pound +@end + +pixel = 1 micrometer = px +xpixel = 1 micrometer = xpx +ypixel = 1 micrometer = ypx +zpixel = 1 micrometer = zpx +simulation_xpixel = 1 micrometer = sxpx +simulation_ypixel = 1 micrometer = sypx +simulation_zpixel = 1 micrometer = szpx + +""" \ No newline at end of file From 7e2c8f8b0762cfeef030e5f931faa32f25f27521 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 22:17:04 +0100 Subject: [PATCH 028/105] Update __init__.py --- deeptrack/__init__.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 858b16fcd..f53a32c9f 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -6,14 +6,16 @@ # Create a UnitRegistry and add custom units. units = UnitRegistry() +del units._units["pixel"] +del units._units["px"] custom_units = [ - "pixel = 1 micrometer = px", ### Can this be erased? - "xpixel = 1 micrometer = xpx", ### why these are defined as 1 um? + "pixel = 1 micrometer = px", + "xpixel = 1 micrometer = xpx", "ypixel = 1 micrometer = ypx", "zpixel = 1 micrometer = zpx", "simulation_xpixel = 1 micrometer = sxpx", "simulation_ypixel = 1 micrometer = sypx", - "simulation_zpixel = 1 micrometer = szpx" + "simulation_zpixel = 1 micrometer = szpx", ] for unit in custom_units: units.define(unit) From 3aa4baa31dde3948b7030167bbf868a786ab18f5 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 22:18:14 +0100 Subject: [PATCH 029/105] Update __init__.py --- deeptrack/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index f53a32c9f..2a75fe82e 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -2,9 +2,10 @@ import lazy_import from pint import UnitRegistry -'''units = UnitRegistry(pint_definitions.split("\n"))'''#TBE +from .backend.pint_definition import pint_definitions +units = UnitRegistry(pint_definitions.split("\n")) -# Create a UnitRegistry and add custom units. +'''# Create a UnitRegistry and add custom units. units = UnitRegistry() del units._units["pixel"] del units._units["px"] @@ -18,7 +19,7 @@ "simulation_zpixel = 1 micrometer = szpx", ] for unit in custom_units: - units.define(unit) + units.define(unit)''' '''# Check if tensorflow is installed without importing it import pkg_resources From 03145b6ecae721729e424888fe4842a6da6d7020 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 23:51:53 +0100 Subject: [PATCH 030/105] Update pint_definition.py --- deeptrack/backend/pint_definition.py | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py index f8137bd07..6487e23fa 100644 --- a/deeptrack/backend/pint_definition.py +++ b/deeptrack/backend/pint_definition.py @@ -1,3 +1,46 @@ +"""Pint constants and units definition for DeepTrack2. + +This file consolidates and extends the default definitions provided by Pint's +`default_en.txt` and `constants_en.txt` files. These files define physical +constants and unit systems based on internationally recognized standards, such +as the International System of Units (SI), and additional systems like CGS, +Planck units, and atomic units. + +Sources: +-------- +- Pint's default unit definitions: + https://github.com/hgrecco/pint/blob/main/pint/default_en.txt +- Pint's default constants definitions: + https://github.com/hgrecco/pint/blob/main/pint/constants_en.txt + +Content: +-------- +- Mathematical Constants: Includes key values like π, Euler's number, + and the natural logarithm of 10. +- Physical Constants: Covers fundamental constants like the speed of light, + Planck constant, and Boltzmann constant. +- Derived Constants: Defines values such as the fine-structure constant and + classical electron radius. +- Units: Provides base and derived units for length, mass, time, energy, etc., + with precise conversion factors. +- Prefixes and Aliases: Defines standard prefixes (e.g., milli-, kilo-, mega-) + and unit aliases to ensure flexibility. +- Unit Systems: Details unit systems, including SI, MKS, CGS, Planck, and + imperial units. +- Contexts and Conversion: Includes context-specific definitions to facilitate + domain-specific conversions. + +Key Modifications: +------------------ +This file is derived from the default Pint files with the adjustments: +1. Groups Removed: Unit group definitions (e.g., `@group`) have been excluded + to avoid conflicts with the definition of pixel. +2. Final Variables Added: Defines constants and variables required for the + project-specific context (e.g., pixel-related units). + +""" + + pint_constants = """ # Default Pint constants definition file # Based on the International System of Units @@ -939,5 +982,4 @@ simulation_xpixel = 1 micrometer = sxpx simulation_ypixel = 1 micrometer = sypx simulation_zpixel = 1 micrometer = szpx - """ \ No newline at end of file From 1f7f4719a19925d353cefef8f7a596263eede0e4 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 23:51:57 +0100 Subject: [PATCH 031/105] Update __init__.py --- deeptrack/__init__.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 2a75fe82e..6fcdcf190 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -1,27 +1,13 @@ # flake8: noqa import lazy_import + from pint import UnitRegistry +from .backend.pint_definitions import pint_definitions -from .backend.pint_definition import pint_definitions +# Create a unit registry with custom pixel-related units. units = UnitRegistry(pint_definitions.split("\n")) -'''# Create a UnitRegistry and add custom units. -units = UnitRegistry() -del units._units["pixel"] -del units._units["px"] -custom_units = [ - "pixel = 1 micrometer = px", - "xpixel = 1 micrometer = xpx", - "ypixel = 1 micrometer = ypx", - "zpixel = 1 micrometer = zpx", - "simulation_xpixel = 1 micrometer = sxpx", - "simulation_ypixel = 1 micrometer = sypx", - "simulation_zpixel = 1 micrometer = szpx", -] -for unit in custom_units: - units.define(unit)''' - -'''# Check if tensorflow is installed without importing it +'''# Check if tensorflow is installed without importing it #TBE import pkg_resources installed = [pkg.key for pkg in pkg_resources.working_set] From 2a0a448f389160e4a492c2cc306957f4e1cb0abb Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Fri, 6 Dec 2024 23:58:25 +0100 Subject: [PATCH 032/105] Update __init__.py --- deeptrack/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 6fcdcf190..5fbdfafe6 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -2,10 +2,10 @@ import lazy_import from pint import UnitRegistry -from .backend.pint_definitions import pint_definitions +from .backend.pint_definition import pint_definition # Create a unit registry with custom pixel-related units. -units = UnitRegistry(pint_definitions.split("\n")) +units = UnitRegistry(pint_definition.split("\n")) '''# Check if tensorflow is installed without importing it #TBE import pkg_resources From de9a2fec0a908b014c3c215f3573d0e702d56efd Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 00:00:50 +0100 Subject: [PATCH 033/105] Update pint_definition.py --- deeptrack/backend/pint_definition.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py index 6487e23fa..a9fbe4303 100644 --- a/deeptrack/backend/pint_definition.py +++ b/deeptrack/backend/pint_definition.py @@ -38,6 +38,15 @@ 2. Final Variables Added: Defines constants and variables required for the project-specific context (e.g., pixel-related units). +Usage: +------ +To create a unit registry with custom pixel-related units: + +>>> from pint import UnitRegistry +>>> from .backend.pint_definition import pint_definition +>>> +>>> units = UnitRegistry(pint_definition.split("\n")) + """ From 6c6a3166d0dc7e06f324f3dd1244d4faa27275b4 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 00:05:31 +0100 Subject: [PATCH 034/105] u --- deeptrack/__init__.py | 4 ++-- deeptrack/backend/pint_definition.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deeptrack/__init__.py b/deeptrack/__init__.py index 5fbdfafe6..ddac02862 100644 --- a/deeptrack/__init__.py +++ b/deeptrack/__init__.py @@ -2,10 +2,10 @@ import lazy_import from pint import UnitRegistry -from .backend.pint_definition import pint_definition +from .backend.pint_definition import pint_definitions # Create a unit registry with custom pixel-related units. -units = UnitRegistry(pint_definition.split("\n")) +units = UnitRegistry(pint_definitions.split("\n")) '''# Check if tensorflow is installed without importing it #TBE import pkg_resources diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py index a9fbe4303..1c75457b0 100644 --- a/deeptrack/backend/pint_definition.py +++ b/deeptrack/backend/pint_definition.py @@ -43,9 +43,9 @@ To create a unit registry with custom pixel-related units: >>> from pint import UnitRegistry ->>> from .backend.pint_definition import pint_definition +>>> from .backend.pint_definition import pint_definitions >>> ->>> units = UnitRegistry(pint_definition.split("\n")) +>>> units = UnitRegistry(pint_definitions.split("\n")) """ From da487abf0c5cdfd8fe7d108acf9fd447fef667de Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 00:36:38 +0100 Subject: [PATCH 035/105] Delete citations.py --- deeptrack/backend/citations.py | 35 ---------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 deeptrack/backend/citations.py diff --git a/deeptrack/backend/citations.py b/deeptrack/backend/citations.py deleted file mode 100644 index baee70f35..000000000 --- a/deeptrack/backend/citations.py +++ /dev/null @@ -1,35 +0,0 @@ -deeptrack_bibtex = """ -@article{Midtvet2021DeepTrack, - author = {Midtvedt,Benjamin and - Helgadottir,Saga and - Argun,Aykut and - Pineda,Jesús and - Midtvedt,Daniel and - Volpe,Giovanni}, - title = {Quantitative digital microscopy with deep learning}, - journal = {Applied Physics Reviews}, - volume = {8}, - number = {1}, - pages = {011310}, - year = {2021}, - doi = {10.1063/5.0034891} -} -""" - -unet_bibtex = """ -@article{DBLP:journals/corr/RonnebergerFB15, - author = {Olaf Ronneberger and - Philipp Fischer and - Thomas Brox}, - title = {U-Net: Convolutional Networks for Biomedical Image Segmentation}, - journal = {CoRR}, - volume = {abs/1505.04597}, - year = {2015}, - url = {http://arxiv.org/abs/1505.04597}, - archivePrefix = {arXiv}, - eprint = {1505.04597}, - timestamp = {Mon, 13 Aug 2018 16:46:52 +0200}, - biburl = {https://dblp.org/rec/journals/corr/RonnebergerFB15.bib}, - bibsource = {dblp computer science bibliography, https://dblp.org} -} -""" \ No newline at end of file From 7ade9699fc754e5c1849ac86440466ff57367ece Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 00:36:42 +0100 Subject: [PATCH 036/105] Update core.py --- deeptrack/backend/core.py | 45 ++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 44b542c29..7ac8f6ed4 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1,12 +1,23 @@ -from copy import copy, deepcopy -import re -from weakref import WeakSet -import numpy as np import operator +from weakref import WeakSet -from .. import utils, image -from .citations import deeptrack_bibtex +import numpy as np +from .. import utils + +citation_Midtvet2021Quantitative = """ +@article{Midtvet2021Quantitative, + author = {Midtvedt, Benjamin and Helgadottir, Saga and Argun, Aykut and + Pineda, Jesús and Midtvedt, Daniel and Volpe, Giovanni}, + title = {Quantitative digital microscopy with deep learning}, + journal = {Applied Physics Reviews}, + volume = {8}, + number = {1}, + pages = {011310}, + year = {2021}, + doi = {10.1063/5.0034891} +} +""" class DeepTrackDataObject: @@ -137,7 +148,7 @@ class DeepTrackNode: __nonelike_default = object() - citation = deeptrack_bibtex + citations = [citation_Midtvet2021Quantitative] @property def action(self): @@ -286,14 +297,22 @@ def recurse_dependencies(self, memory=None): yield from dependency.recurse_dependencies(memory=memory) def get_citations(self): - """Gets a set of citations for all objects in a pipeline.""" - cites = {self.citation} + """Get citations for all objects in a pipeline.""" + + # Initialize citations as a set of elements from self.citations. + citations = set(self.citations) if self.citations else set() + + # Recurse through dependencies to collect all citations. for dep in self.recurse_dependencies(): for obj in type(dep).mro(): - if hasattr(obj, "citation"): - cites.add(obj.citation) - - return cites + if hasattr(obj, "citations"): + # Add the citations of the current object. + citations.update( + obj.citations if isinstance(obj.citations, list) + else [obj.citations] + ) + + return citations def __call__(self, _ID=()): From 7b06a47330ea7c77c243951cde73af9b190836f6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 00:54:21 +0100 Subject: [PATCH 037/105] Update core.py --- deeptrack/backend/core.py | 145 +++++++++++++++++++++++++++++++++++--- 1 file changed, 137 insertions(+), 8 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 7ac8f6ed4..377dfc4fc 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1,3 +1,67 @@ +"""DeepTrack2 core package. + +This package provides the core classes and functionality required for managing, +processing, and evaluating data within the DeepTrack framework. It is designed +to support building flexible pipelines for scientific data analysis and machine +learning applications. + +Main Features +------------- +1. **Data Management**: + - `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, validate, and manage data with dependency tracking. + - Enables nested structures and flexible indexing for complex data hierarchies. + +2. **Computational Graphs**: + - `DeepTrackNode` forms the backbone of computation pipelines, representing nodes in a computation graph. + - Nodes support lazy evaluation, dependency tracking, and caching to optimize performance. + - Implements mathematical operators for easy composition of computational graphs. + +3. **Citations**: + - Supports citing the relevant publication (`Midtvedt et al., 2021`) to ensure proper attribution. + +4. **Utilities**: + - Includes helper functions like `equivalent` and `create_node_with_operator` to streamline graph operations. + +Package Structure +----------------- +- **Data Containers**: + - `DeepTrackDataObject`: A basic container for data with validation status. + - `DeepTrackDataDict`: Stores multiple data objects indexed by unique access IDs, enabling nested data storage. + +- **Computation Nodes**: + - `DeepTrackNode`: Represents a node in a computation graph, capable of lazy evaluation, caching, and dependency management. + +- **Citation Management**: + - Provides support for including citations in pipelines for academic and scientific use. + +- **Utilities**: + - Functions for equivalence checking and operator-based node creation simplify working with computation graphs. + +Dependencies +------------ +- `numpy`: Provides efficient numerical operations. +- `operator`: Enables operator overloading for computation nodes. +- `weakref.WeakSet`: Manages relationships between nodes without creating circular dependencies. + +Usage +----- +This package is the core component of the DeepTrack framework. It enables users to: +- Construct flexible and efficient computational pipelines. +- Manage data and dependencies in a hierarchical structure. +- Perform lazy evaluations for performance optimization. + +Example +------- +```python +# Create a DeepTrackNode with an action +node = DeepTrackNode(lambda x: x**2) +node.store(5) + +# Retrieve the stored value +print(node.current_value()) # Output: 25 + +""" + import operator from weakref import WeakSet @@ -5,6 +69,7 @@ from .. import utils + citation_Midtvet2021Quantitative = """ @article{Midtvet2021Quantitative, author = {Midtvedt, Benjamin and Helgadottir, Saga and Argun, Aykut and @@ -19,33 +84,97 @@ } """ -class DeepTrackDataObject: - - """Atomic data container for deeptrack. - The purpose of this is to store some data, and if that data is valid. - Data is not valid, if some dependency of the data has been changed or otherwise made invalid - since the last time the data was validated. +class DeepTrackDataObject: + """Basic data container for DeepTrack2. + + This class serves as a simple container for storing data and managing its + validity. It is designed to track whether the data remains valid, based on + changes in dependencies or other external factors that might invalidate the + data since it was last updated. + + Attributes + ---------- + data : any + The stored data. Default is `None`. + valid : bool + A flag indicating whether the stored data is valid. Default is `False`. + + Methods + ------- + store(data) + Stores data in the container and marks it as valid. + current_value() + Returns the currently stored data. + is_valid() + Checks if the stored data is valid. + invalidate() + Marks the data as invalid. + validate() + Marks the data as valid. + """ def __init__(self): + """Initialize the container without data. + + The `data` attribute is set to `None`, and the `valid` attribute is set + to `False` by default. + + """ self.data = None self.valid = False def store(self, data): - self.valid = True + """Store data in the container and mark it as valid. + + Parameters + ---------- + data : any + The data to be stored in the container. + + """ self.data = data + self.valid = True def current_value(self): + """Retrieve the currently stored data. + + Returns + ------- + any + The data stored in the container. + + """ return self.data def is_valid(self): + """Check if the stored data is valid. + + Returns + ------- + bool + `True` if the data is valid, `False` otherwise. + + """ return self.valid def invalidate(self): + """Mark the stored data as invalid. + + This method sets the `valid` attribute to `False`, indicating that the + data is no longer reliable. + + """ self.valid = False def validate(self): + """Mark the stored data as valid. + + This method sets the `valid` attribute to `True`, indicating that the + data is considered up-to-date and reliable. + + """ self.valid = True @@ -426,4 +555,4 @@ def create_node_with_operator(op, a, b): a.add_child(new) b.add_child(new) - return new + return new \ No newline at end of file From 582136bd5962d67ca7b651705671e5d474e3fde6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 07:21:25 +0100 Subject: [PATCH 038/105] Update core.py --- deeptrack/backend/core.py | 48 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 377dfc4fc..b43eacf5a 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -66,6 +66,7 @@ from weakref import WeakSet import numpy as np +from typing import Any from .. import utils @@ -95,86 +96,75 @@ class DeepTrackDataObject: Attributes ---------- - data : any - The stored data. Default is `None`. + data : Any + The stored data. Default is `None`. Can hold any data type. valid : bool A flag indicating whether the stored data is valid. Default is `False`. Methods ------- - store(data) + store(data : Any) Stores data in the container and marks it as valid. - current_value() + current_value() -> Any Returns the currently stored data. - is_valid() + is_valid() -> bool Checks if the stored data is valid. invalidate() Marks the data as invalid. validate() Marks the data as valid. - """ + # Attributes. + data: Any + valid: bool + def __init__(self): """Initialize the container without data. The `data` attribute is set to `None`, and the `valid` attribute is set to `False` by default. - """ self.data = None self.valid = False - def store(self, data): + def store(self, data: Any) -> None: """Store data in the container and mark it as valid. Parameters ---------- - data : any + data : Any The data to be stored in the container. - """ self.data = data self.valid = True - def current_value(self): + def current_value(self) -> Any: """Retrieve the currently stored data. Returns ------- - any + Any The data stored in the container. - """ return self.data - def is_valid(self): + def is_valid(self) -> bool: """Check if the stored data is valid. Returns ------- bool `True` if the data is valid, `False` otherwise. - """ return self.valid - def invalidate(self): - """Mark the stored data as invalid. - - This method sets the `valid` attribute to `False`, indicating that the - data is no longer reliable. - - """ + def invalidate(self) -> None: + """Mark the stored data as invalid.""" self.valid = False - def validate(self): - """Mark the stored data as valid. - - This method sets the `valid` attribute to `True`, indicating that the - data is considered up-to-date and reliable. - - """ + def validate(self) -> None: + """Mark the stored data as valid.""" self.valid = True From 60a97f4030604d3d52a9f3a5cef75089a5b614ad Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 08:03:39 +0100 Subject: [PATCH 039/105] Update core.py --- deeptrack/backend/core.py | 261 +++++++++++++++++++++++++++++++------- 1 file changed, 218 insertions(+), 43 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index b43eacf5a..70a045a33 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -66,7 +66,7 @@ from weakref import WeakSet import numpy as np -from typing import Any +from typing import Any, Dict, Optional, Tuple, Union from .. import utils @@ -169,91 +169,266 @@ def validate(self) -> None: class DeepTrackDataDict: + """Stores multiple data objects indexed by a tuple of integers (access ID). + + This class allows a single object to store multiple `DeepTrackDataObject` + instances concurrently, each associated with a unique tuple of integers + (the access ID). This is particularly useful for handling sequences of data + or nested structures, as required by features like `Repeat`. + + The default access ID is an empty tuple `()`. The length of the IDs stored + must be consistent once an entry is created. If an ID longer than the + stored length is requested, the request is trimmed. If an ID shorter than + what is stored is requested, a dictionary slice containing all matching + entries is returned. This mechanism supports flexible indexing of nested + data and ensures that dependencies at various nesting depths can be + correctly handled. + + Example + ------- + Consider the following structure, where `Repeat` is a feature that creates + multiple instances of another feature: - """Stores multiple data objects indexed by an access id. - - The purpose of this class is to allow a single object to store multiple - data objects at once. This is necessary for sequences and the feature `Repeat`. + >>> F = Repeat(Repeat(DummyFeature(prop=np.random.rand), 2), 2) - The access id is a tuple of integers. Consider the following example:: + Here, `F` contains 2 * 2 = 4 instances of the feature `prop`. + These can be accessed using the IDs: + (0, 0), (0, 1), (1, 0), and (1, 1). - F = Repeat( - Repeat(DummyFeature(prop = np.random.rand), 2), - 2 - ) + In this nested structure: + - (0, 0) refers to the first repeat of the outer feature and the first + repeat of the inner feature. + - (0, 1) refers to the first repeat of the outer feature and the second + repeat of the inner feature. + And so forth, resolving nested structures via tuples of indices. + + Attributes + ---------- + keylength : int or None + The length of the IDs currently stored. Set when the first entry is + created. If `None`, no entries have been created yet, and any ID length + is valid. + dict : Dict[Tuple[int, ...], DeepTrackDataObject] + A dictionary mapping tuples of integers (IDs) to `DeepTrackDataObject` + instances. - `F` contains 2*2=4 instances of the feature prop. They would be accessed using the IDs - (0, 0), (0, 1), (1, 0), and (1, 1). In this way nested structures are resolved. + Methods + ------- + invalidate() + Marks all stored data objects as invalid. + validate() + Marks all stored data objects as valid. + valid_index(_ID : tuple) -> bool + Checks if the given ID is valid for the current configuration. + create_index(_ID : tuple = ()) + Creates an entry for the given ID if it does not exist. + __getitem__(_ID : tuple) -> DeepTrackDataObject' + | Dict[Tuple[int, ...], 'DeepTrackDataObject'] + Retrieves data associated with the ID. Can return a + `DeepTrackDataObject` or a dict of matching entries if `_ID` is shorter + than `keylength`. + __contains__(_ID : tuple) -> bool + Checks if the given ID exists in the dictionary. + + """ - The default is an empty tuple. + # Attributes. + keylength: Optional[int] + dict: Dict[Tuple[int, ...], DeepTrackDataObject] - All IDs of a DataDict need to be of the same length. If a DataDict has value stored to the None ID, it can not store any other IDs. - If a longer ID is requested than what is stored, the request is trimmed to the length of the stored IDs. This is important to - correctly handle dependencies to lower depths of nested structures. + def __init__(self): + """Initialize the data dictionary. - If a shorter ID is requested than what is stored, the a slice of the DataDict is returned with all IDs matching the request. + Initializes `keylength` to `None` and `dict` to an empty dictionary, + indicating no data objects are currently stored. + + """ + + self.keylength = None + self.dict = {} + def invalidate(self) -> None: + """Mark all stored data objects as invalid. + Calls `invalidate()` on every `DeepTrackDataObject` in the dictionary. + + """ + + for dataobject in self.dict.values(): + dataobject.invalidate() - """ + def validate(self) -> None: + """Mark all stored data objects as valid. - def __init__(self): - self.keylength = None - self.dict = {} + Calls `validate()` on every `DeepTrackDataObject` in the dictionary. + + """ + + for dataobject in self.dict.values(): + dataobject.validate() - def invalidate(self): - # self.dict = {} - for d in self.dict.values(): - d.invalidate() + def valid_index(self, _ID: Tuple[int, ...]) -> bool: + """Check if a given ID is valid for this data dictionary. - def validate(self): - for d in self.dict.values(): - d.validate() + Parameters + ---------- + _ID : Tuple[int, ...] + The index to check, consisting of a tuple of integers. - def valid_index(self, _ID): - assert isinstance(_ID, tuple), f"Data index {_ID} is not a tuple" + Returns + ------- + bool + `True` if the ID is valid given the current configuration, `False` + otherwise. + + Raises + ------ + AssertionError + If `_ID` is not a tuple of integers. The error message includes the + actual `_ID` value and the types of its elements for easier + debugging. + + Notes + ----- + - If `keylength` is `None`, any tuple ID is considered valid since no + entries have been created yet. + - If `_ID` already exists in `dict`, it is automatically valid. + - Otherwise, `_ID` must have the same length as `keylength` to be + considered valid. + + """ + + assert ( + isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) + ), ( + f"Data index {_ID} is not a tuple of integers. " + f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." + ) + # If keylength has not yet been set, all indexes are valid. if self.keylength is None: - # If keylength has not yet been set, all indexes are valid return True + # If index is already stored, always valid. if _ID in self.dict: - # If index is a key, always valid return True - # Otherwise, check key is correct length + # Otherwise, the ID length must match the established keylength. return len(_ID) == self.keylength - def create_index(self, _ID=()): + def create_index(self, _ID: Tuple[int, ...] = ()) -> None: + """Create a new data entry for the given ID if not already existing. - assert isinstance(_ID, tuple), f"Data index {_ID} is not a tuple" + Parameters + ---------- + _ID : Tuple[int, ...], optional + A tuple of integers representing the ID for the data entry. + Default is `()`, which represents a root-level data entry with no + nesting. + + Raises + ------ + AssertionError + - If `_ID` is not a tuple of integers. The error message includes + the value of `_ID` and the types of its elements. + - If `_ID` is not a valid index according to the current + configuration. + + Notes + ----- + - If `keylength` is `None`, it is set to the length of `_ID`. Once + established, all subsequently created IDs must have this same length. + - If `_ID` is already in `dict`, no new entry is created. + - Each newly created index is associated with a fresh + `DeepTrackDataObject`. + + """ + + # Ensure `_ID` is a tuple of integers. + assert ( + isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) + ), ( + f"Data index {_ID} is not a tuple of integers. " + f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." + ) + # If `_ID` already exists, do nothing. if _ID in self.dict: return - assert self.valid_index(_ID), f"{_ID} is not a valid index for dict {self.dict}" + # Check if the given `_ID` is valid. + assert self.valid_index(_ID), ( + f"{_ID} is not a valid index for current dictionary configuration." + ) + # If `keylength` is not set, initialize it with current ID's length. if self.keylength is None: self.keylength = len(_ID) + # Create a new DeepTrackDataObject for this ID. self.dict[_ID] = DeepTrackDataObject() - def __getitem__(self, _ID): - assert isinstance(_ID, tuple), f"Data index {_ID} is not a tuple" + def __getitem__( + self, + _ID: Tuple[int, ...], + ) -> Union['DeepTrackDataObject', + Dict[Tuple[int, ...], 'DeepTrackDataObject']]: + """Retrieve data associated with a given ID. + + Parameters + ---------- + _ID : Tuple[int, ...] + The ID for the requested data. + + Returns + ------- + DeepTrackDataObject or dict + If `_ID` matches `keylength`, returns the corresponding + `DeepTrackDataObject`. + If `_ID` is longer than `keylength`, the request is trimmed to + match `keylength`. + If `_ID` is shorter than `keylength`, returns a dict of all entries + whose IDs match the given `_ID` prefix. + + Raises + ------ + AssertionError + If `_ID` is not a tuple of integers. + KeyError + If the dictionary is empty (`keylength` is `None`). + """ + assert ( + isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) + ), ( + f"Data index {_ID} is not a tuple of integers. " + f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." + ) if self.keylength is None: - raise KeyError("Indexing an empty dict") - + raise KeyError("Indexing an empty dict.") + if len(_ID) == self.keylength: return self.dict[_ID] - elif len(_ID) > self.keylength: + # Trim the requested ID to match keylength. return self[_ID[: self.keylength]] - else: + # Return a slice of all items matching the shorter ID prefix. return {k: v for k, v in self.dict.items() if k[: len(_ID)] == _ID} - def __contains__(self, _ID): + def __contains__(self, _ID: Tuple[int, ...]) -> bool: + """Check if a given ID exists in the dictionary. + + Parameters + ---------- + _ID : Tuple[int, ...] + The ID to check. + + Returns + ------- + bool + `True` if the ID exists, `False` otherwise. + """ return _ID in self.dict From 57122c244f93bc542bd3e419eb7d6ec791674fc0 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 08:15:56 +0100 Subject: [PATCH 040/105] Update core.py --- deeptrack/backend/core.py | 121 ++++++++++++++++++++++++++++---------- 1 file changed, 90 insertions(+), 31 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 70a045a33..67d49da69 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -20,7 +20,7 @@ - Supports citing the relevant publication (`Midtvedt et al., 2021`) to ensure proper attribution. 4. **Utilities**: - - Includes helper functions like `equivalent` and `create_node_with_operator` to streamline graph operations. + - Includes helper functions like `_equivalent` and `_create_node_with_operator` to streamline graph operations. Package Structure ----------------- @@ -538,7 +538,7 @@ def set_value(self, value, _ID=()): # If set to same value, no need to invalidate if not ( - self.is_valid(_ID=_ID) and equivalent(value, self.data[_ID].current_value()) + self.is_valid(_ID=_ID) and _equivalent(value, self.data[_ID].current_value()) ): self.invalidate(_ID=_ID) self.store(value, _ID=_ID) @@ -638,64 +638,86 @@ def __getitem__(self, idx): # node-node operators def __add__(self, other): - return create_node_with_operator(operator.__add__, self, other) + return _create_node_with_operator(operator.__add__, self, other) def __radd__(self, other): - return create_node_with_operator(operator.__add__, other, self) + return _create_node_with_operator(operator.__add__, other, self) def __sub__(self, other): - return create_node_with_operator(operator.__sub__, self, other) + return _create_node_with_operator(operator.__sub__, self, other) def __rsub__(self, other): - return create_node_with_operator(operator.__sub__, other, self) + return _create_node_with_operator(operator.__sub__, other, self) def __mul__(self, other): - return create_node_with_operator(operator.__mul__, self, other) + return _create_node_with_operator(operator.__mul__, self, other) def __rmul__(self, other): - return create_node_with_operator(operator.__mul__, other, self) + return _create_node_with_operator(operator.__mul__, other, self) def __truediv__(self, other): - return create_node_with_operator(operator.__truediv__, self, other) + return _create_node_with_operator(operator.__truediv__, self, other) def __rtruediv__(self, other): - return create_node_with_operator(operator.__truediv__, other, self) + return _create_node_with_operator(operator.__truediv__, other, self) def __floordiv__(self, other): - return create_node_with_operator(operator.__floordiv__, self, other) + return _create_node_with_operator(operator.__floordiv__, self, other) def __rfloordiv__(self, other): - return create_node_with_operator(operator.__floordiv__, other, self) + return _create_node_with_operator(operator.__floordiv__, other, self) def __lt__(self, other): - return create_node_with_operator(operator.__lt__, self, other) + return _create_node_with_operator(operator.__lt__, self, other) def __rlt__(self, other): - return create_node_with_operator(operator.__lt__, other, self) + return _create_node_with_operator(operator.__lt__, other, self) def __gt__(self, other): - return create_node_with_operator(operator.__gt__, self, other) + return _create_node_with_operator(operator.__gt__, self, other) def __rgt__(self, other): - return create_node_with_operator(operator.__gt__, other, self) + return _create_node_with_operator(operator.__gt__, other, self) def __le__(self, other): - return create_node_with_operator(operator.__le__, self, other) + return _create_node_with_operator(operator.__le__, self, other) def __rle__(self, other): - return create_node_with_operator(operator.__le__, other, self) + return _create_node_with_operator(operator.__le__, other, self) def __ge__(self, other): - return create_node_with_operator(operator.__ge__, self, other) + return _create_node_with_operator(operator.__ge__, self, other) def __rge__(self, other): - return create_node_with_operator(operator.__ge__, other, self) + return _create_node_with_operator(operator.__ge__, other, self) -def equivalent(a, b): - # This is a bare-bones implementation to check if two objects are equivalent. - # We can implement more cases to reduce updates. +def _equivalent(a, b): + """Check if two objects are equivalent (internal function). + This is a basic implementation to determine equivalence between two + objects. Additional cases can be implemented as needed to refine this + behavior. + + Parameters + ---------- + a : Any + The first object to compare. + b : Any + The second object to compare. + + Returns + ------- + bool + `True` if the objects are equivalent, `False` otherwise. + + Notes + ----- + - If `a` and `b` are the same object (identity check), they are considered + equivalent. + - If both `a` and `b` are empty lists, they are considered equivalent. + """ + if a is b: return True @@ -705,19 +727,56 @@ def equivalent(a, b): return False -def create_node_with_operator(op, a, b): - """Creates a new node with the given operator and operands.""" +def _create_node_with_operator(op, a, b): + """Create a new computation node using a given operator and operands. + + This internal helper function constructs a `DeepTrackNode` that represents + the application of the specified operator to two operands. If the operands + are not already `DeepTrackNode` instances, they are converted to nodes. + Parameters + ---------- + op : Callable + The operator function to apply. + a : Any + First operand. If not a `DeepTrackNode`, it will be wrapped in one. + b : Any + Second operand. If not a `DeepTrackNode`, it will be wrapped in one. + + Returns + ------- + DeepTrackNode + A new `DeepTrackNode` that applies the operator `op` to the values of + nodes `a` and `b`. + + Notes + ----- + - This function establishes bidirectional relationships between the new + node and its operands: + - The new node is added as a child of both `a` and `b`. + - The operands are added as dependencies of the new node. + - The operator `op` is applied lazily, meaning it will be evaluated when + the new node is called. + + """ + + # Ensure `a` is a `DeepTrackNode`. Wrap it if necessary. if not isinstance(a, DeepTrackNode): a = DeepTrackNode(a) + # Ensure `b` is a `DeepTrackNode`. Wrap it if necessary. if not isinstance(b, DeepTrackNode): b = DeepTrackNode(b) - new = DeepTrackNode(lambda _ID=(): op(a(_ID=_ID), b(_ID=_ID))) - new.add_dependency(a) - new.add_dependency(b) - a.add_child(new) - b.add_child(new) + # New node that applies the operator `op` to the outputs of `a` and `b`. + new_node = DeepTrackNode(lambda _ID=(): op(a(_ID=_ID), b(_ID=_ID))) + + # Establish dependency relationships between the nodes. + new_node.add_dependency(a) + new_node.add_dependency(b) + + # Set the new node as a child of both `a` and `b`. + a.add_child(new_node) + b.add_child(new_node) - return new \ No newline at end of file + return new_node \ No newline at end of file From a6ab285a0f732cc7d29977f55e52f86dda3152f6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 08:22:26 +0100 Subject: [PATCH 041/105] Update core.py --- deeptrack/backend/core.py | 99 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 67d49da69..e5ec15f48 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -636,62 +636,159 @@ def __getitem__(self, idx): self.add_child(node) return node - # node-node operators + # Node-node operators. + # These methods define arithmetic and comparison operations for + # DeepTrackNode objects. Each operation creates a new DeepTrackNode that + # represents the result of applying the corresponding operator to `self` + # and `other`. The operators are applied lazily and will be computed only + # when the resulting node is evaluated. + def __add__(self, other): + """Add node to other node or value. + + Operation performed: + result = self + other + """ return _create_node_with_operator(operator.__add__, self, other) def __radd__(self, other): + """Add other value to node (right-hand). + + Operation performed: + result = other + self + """ return _create_node_with_operator(operator.__add__, other, self) def __sub__(self, other): + """Subtract other node or value from node. + + Operation performed: + result = self - other + """ return _create_node_with_operator(operator.__sub__, self, other) def __rsub__(self, other): + """Subtract node from other value (right-hand). + + Operation performed: + result = other - self + """ return _create_node_with_operator(operator.__sub__, other, self) def __mul__(self, other): + """Multiply node by other node or value. + + Operation performed: + result = self * other + """ return _create_node_with_operator(operator.__mul__, self, other) def __rmul__(self, other): + """Multiply other value by node (right-hand). + + Operation performed: + result = other * self + """ return _create_node_with_operator(operator.__mul__, other, self) def __truediv__(self, other): + """Divide node by other node or value. + + Operation performed: + result = self / other + """ return _create_node_with_operator(operator.__truediv__, self, other) def __rtruediv__(self, other): + """Divide other value by node (right-hand). + + Operation performed: + result = other / self + """ return _create_node_with_operator(operator.__truediv__, other, self) def __floordiv__(self, other): + """Perform floor division of node by other node or value. + + Operation performed: + result = self // other + """ return _create_node_with_operator(operator.__floordiv__, self, other) def __rfloordiv__(self, other): + """Perform floor division of other value by node (right-hand). + + Operation performed: + result = other // self + """ return _create_node_with_operator(operator.__floordiv__, other, self) def __lt__(self, other): + """Check if node is less than other node or value. + + Operation performed: + result = self < other + """ return _create_node_with_operator(operator.__lt__, self, other) def __rlt__(self, other): + """Check if other value is less than node (right-hand). + + Operation performed: + result = other < self + """ return _create_node_with_operator(operator.__lt__, other, self) def __gt__(self, other): + """Check if node is greater than other node or value. + + Operation performed: + result = self > other + """ return _create_node_with_operator(operator.__gt__, self, other) def __rgt__(self, other): + """Check if other value is greater than node (right-hand). + + Operation performed: + result = other > self + """ return _create_node_with_operator(operator.__gt__, other, self) def __le__(self, other): + """Check if node is less than or equal to other node or value. + + Operation performed: + result = self <= other + """ return _create_node_with_operator(operator.__le__, self, other) def __rle__(self, other): + """Check if other value is less than or equal to node (right-hand). + + Operation performed: + result = other <= self + """ return _create_node_with_operator(operator.__le__, other, self) def __ge__(self, other): + """Check if node is greater than or equal to other node or value. + + Operation performed: + result = self >= other + """ return _create_node_with_operator(operator.__ge__, self, other) def __rge__(self, other): + """Check if other value is greater than or equal to node (right-hand). + + Operation performed: + result = other >= self + """ return _create_node_with_operator(operator.__ge__, other, self) + def _equivalent(a, b): """Check if two objects are equivalent (internal function). From 724f1bf572fca63643ddd1a551a7294b26def1ea Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:08:36 +0100 Subject: [PATCH 042/105] Update features.py --- deeptrack/features.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeptrack/features.py b/deeptrack/features.py index bd3691e3f..d60f0822c 100644 --- a/deeptrack/features.py +++ b/deeptrack/features.py @@ -92,7 +92,7 @@ class Feature(DeepTrackNode): # A None-safe default value to compare against - __nonelike_default = object() + __none_like_default = object() _wrap_array_with_image = False From 795449516dc305fb51861a22c994688b3518c94d Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:08:38 +0100 Subject: [PATCH 043/105] Update core.py --- deeptrack/backend/core.py | 492 ++++++++++++++++++++++++++++++++++---- 1 file changed, 448 insertions(+), 44 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index e5ec15f48..774cc7e6f 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -66,7 +66,7 @@ from weakref import WeakSet import numpy as np -from typing import Any, Dict, Optional, Tuple, Union +from typing import Any, Dict, Iterator, Optional, Set, Tuple, Union from .. import utils @@ -435,86 +435,323 @@ def __contains__(self, _ID: Tuple[int, ...]) -> bool: class DeepTrackNode: """Object corresponding to a node in a computation graph. - This is a base class for all nodes in a computation graph. It is used to store and compute data. - When evaluated, the node will call the `action` method. The action method defines a way to calculate the next data. - If the data is already present, it will not be recalculated. + This class represents a node within a computation graph, where each node + can store data and compute new values based on its dependencies. The value + of a node is computed by calling its `action` method, which can depend on + the data stored in this node or in other nodes (dependencies). + + Key Features + ------------- + - Lazy Evaluation: + The node’s value is only computed when needed and cached, avoiding + unnecessary recomputations. + - Dependency Tracking: + Nodes keep track of their dependencies and children, enabling + hierarchical and iterative computations. + - ID-Based Indexing: + Data can be stored and retrieved using `_ID` tuples, allowing for + nested and structured indexing of data. + - Citations: + Each node can contribute references (citations), making research + reproducibility and attribution more straightforward. + + Attributes + ---------- + data : DeepTrackDataDict + A dictionary-like object for storing data, indexed by tuples of + integers. + children : WeakSet[DeepTrackNode] + A set of nodes that depend on this node. Changing this node may affect + its children. + dependencies : WeakSet[DeepTrackNode] + A set of nodes on which this node depends. If any dependency changes, + the validity of this node’s data may be affected. + _action : Callable + Function or lambda defining how to compute new values for this node. + If `_accepts_ID` is `True`, `action` is called with `_ID` as parameter. + _accepts_ID : bool + Indicates whether the `action` function accepts an `_ID` parameter. + _all_subchildren : set + Set of all nodes in the subtree rooted at this node, including itself. + + Methods + ------- + action : Callable + The node’s computation function. When set, checks if `_ID` is accepted. + add_child(other: DeepTrackNode) -> DeepTrackNode + Adds a `DeepTrackNode` as a child of this node. + add_dependency(other: DeepTrackNode) -> DeepTrackNode + Adds a `DeepTrackNode` as a dependency of this node. + store(data: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode + Stores computed data associated with this node. + is_valid(_ID: Tuple[int, ...] = ()) -> bool + Checks if data for the given `_ID` is currently valid. + valid_index(_ID: Tuple[int, ...]) -> bool + Checks if `_ID` is a valid index for this node’s data. + invalidate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode + Marks this node’s data (and that of its children) as invalid. + validate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode + Marks this node’s data (and that of its children) as valid. + _update() -> DeepTrackNode + Resets data for all children of all dependencies, often after a change. + set_value(value: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode + Sets a value for this node’s data, invalidating first if needed. + previous(_ID: Tuple[int, ...] = ()) -> Any + Retrieves the previously stored value for the given `_ID`. + recurse_children(memory: Set['DeepTrackNode'] = set()) + -> Set['DeepTrackNode'] + Returns all subchildren of this node. Used for dependency traversal. + old_recurse_children(memory: Optional[List['DeepTrackNode']] = None) + -> Iterator['DeepTrackNode'] + A legacy method that yields nodes in a depth-first manner. + recurse_dependencies(memory: Optional[List['DeepTrackNode']] = None) + -> Iterator['DeepTrackNode'] + Yields all dependencies of this node, ensuring each node is visited + only once. + get_citations() -> Set[str] + Gathers citations from this node and all its dependencies. + __call__(_ID: Tuple[int, ...] = ()) -> Any + Evaluates the node by calling `action` and stores/retrieves the result. + current_value(_ID: Tuple[int, ...] = ()) -> Any + Retrieves the currently stored value for `_ID`. + __hash__() -> int + Returns a unique hash for this node based on its `id`. + __getitem__(idx: Any) -> DeepTrackNode + Allows indexing into the result of this node, returning a new node that + applies indexing to the computed data. + """ - __nonelike_default = object() + # A unique sentinel object for default action. + __none_like_default = object() + + # Citations associated with this DeepTrack2. citations = [citation_Midtvet2021Quantitative] @property def action(self): + """Callable: The function that computes this node’s value. + + When accessed, returns the current action. This is often a lambda or + function that takes `_ID` as an optional parameter if `_accepts_ID` is + True. + + """ + return self._action @action.setter def action(self, value): + """Set the action used to compute this node’s value. + + Parameters + ---------- + value : Callable + A function or lambda to be used for computing the node’s value. If + the function’s signature includes `_ID`, this node will pass `_ID` + when calling `action`. + """ self._action = value self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") - def __init__(self, action=__nonelike_default, **kwargs): + def __init__(self, action=__none_like_default, **kwargs): + """Initialize a new DeepTrackNode. + + Parameters + ---------- + action : Callable or object, optional + The action used to compute this node’s value. If not provided or if + __none_like_default is used, defaults to a lambda that does + nothing. + + **kwargs : dict + Additional arguments for subclasses or extended functionality. + + """ + self.data = DeepTrackDataDict() self.children = WeakSet() self.dependencies = WeakSet() - self._action = lambda: None + self._action = lambda: None # Default no-op action. - if action is not self.__nonelike_default: + # If action is provided, set it. If it's callable, use it directly; + # otherwise, wrap it in a lambda. + if action is not self.__none_like_default: if callable(action): self.action = action else: self.action = lambda: action - self._accepts_ID = utils.get_kwarg_names(self.action).__contains__("_ID") + # Check if action accepts `_ID`. + self._accepts_ID = \ + utils.get_kwarg_names(self.action).__contains__("_ID") + + # Call super init in case of multiple inheritance. super().__init__(**kwargs) + # Keep track of all subchildren, including this node. self._all_subchildren = set() self._all_subchildren.add(self) - def add_child(self, other): + def add_child(self, other) -> 'DeepTrackNode': + """Add a child node, indicating that `other` depends on this node. + + Parameters + ---------- + other : DeepTrackNode + The node that depends on this node. + + Returns + ------- + self : DeepTrackNode + Returns the current node for chaining. + + Notes + ----- + Adding a child also updates `_all_subchildren` for this node and all + its dependencies. Ensures that dependency and child relationships + remain consistent. + + """ + self.children.add(other) if not self in other.dependencies: - other.add_dependency(self) + other.add_dependency(self) # Ensure bidirectional relationship. + # Get all subchildren of `other` and add `other` itself. subchildren = other._all_subchildren.copy() subchildren.add(other) + # Merge all these subchildren into this node’s subtree. self._all_subchildren = self._all_subchildren.union(subchildren) for parent in self.recurse_dependencies(): - parent._all_subchildren = parent._all_subchildren.union(subchildren) + parent._all_subchildren = \ + parent._all_subchildren.union(subchildren) return self - def add_dependency(self, other): + def add_dependency(self, other) -> 'DeepTrackNode': + """Add a dependency to this node. + + Parameters + ---------- + other : DeepTrackNode + The node that this node depends on. If `other` changes, this node’s + data may become invalid. + + Returns + ------- + self : DeepTrackNode + Returns the current node for chaining. + + """ + self.dependencies.add(other) - other.add_child(self) + other.add_child(self) # Ensure the child relationship is also set. return self - def store(self, data, _ID=()): + def store(self, data, _ID=()) -> 'DeepTrackNode': + """Store computed data in this node. + Parameters + ---------- + data : Any + The data to store. + _ID : Tuple[int, ...], optional + The index for this data. Default is the empty tuple, indicating a + root-level entry. + + Returns + ------- + self : DeepTrackNode + + """ + + # Create the index if necessary, then store data in it. self.data.create_index(_ID) self.data[_ID].store(data) return self - def is_valid(self, _ID=()): + def is_valid(self, _ID=()) -> bool: + """Check if data for the given ID is valid. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID to check validity for. + + Returns + ------- + bool + `True` if data at `_ID` is valid, otherwise `False`. + + """ + try: return self.data[_ID].is_valid() except (KeyError, AttributeError): return False - def valid_index(self, _ID): + def valid_index(self, _ID) ->bool: + """Check if `_ID` is a valid index for this node’s data. + + Parameters + ---------- + _ID : Tuple[int, ...] + The ID to validate. + + Returns + ------- + bool + `True` if `_ID` is valid, otherwise `False`. + + """ return self.data.valid_index(_ID) - def invalidate(self, _ID=()): + def invalidate(self, _ID=()) -> bool: + """Mark this node’s data and all its children’s data as invalid. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID to invalidate. Default is empty tuple, indicating + potentially the full dataset. + + Returns + ------- + self : DeepTrackNode + + """ + + # Invalidate data for all children of this node. + for child in self.recurse_children(): child.data.invalidate() return self - def validate(self, _ID=()): + def validate(self, _ID=()) -> 'DeepTrackNode': + """Mark this node’s data and all its children’s data as valid. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID to validate. Default is empty tuple. + + Returns + ------- + self : DeepTrackNode + + Notes + ----- + If a child does not have the specified `_ID`, it is ignored. + + """ + for child in self.recurse_children(): try: child.data[_ID].validate() @@ -523,75 +760,181 @@ def validate(self, _ID=()): return self - def _update(self): - # Pre-instantiate memory for optimization + def _update(self) -> 'DeepTrackNode': + """Internal method to reset data in all dependent children. + + This method resets `data` for all children of each dependency, + effectively clearing cached values to force a recomputation on the next + evaluation. + + Returns + ------- + self : DeepTrackNode + + """ + + # Pre-instantiate memory for optimization used to avoid repeated + # processing of the same nodes. child_memory = [] + # For each dependency, reset data in all of its children. for dependency in self.recurse_dependencies(): for dep_child in dependency.recurse_children(memory=child_memory): dep_child.data = DeepTrackDataDict() return self - def set_value(self, value, _ID=()): + def set_value(self, value, _ID=()) -> 'DeepTrackNode': + """Set a value for this node’s data at `_ID`. - # If set to same value, no need to invalidate + If the value is different from the currently stored one (or if it is + invalid), it will invalidate the old data before storing the new one. + Parameters + ---------- + value : Any + The value to store. + _ID : Tuple[int, ...], optional + The ID at which to store the value. + + Returns + ------- + self : DeepTrackNode + + """ + + # Check if current value is equivalent. If not, invalidate and store + # the new value. If set to same value, no need to invalidate if not ( - self.is_valid(_ID=_ID) and _equivalent(value, self.data[_ID].current_value()) + self.is_valid(_ID=_ID) + and _equivalent(value, self.data[_ID].current_value()) ): self.invalidate(_ID=_ID) self.store(value, _ID=_ID) return self - def previous(self, _ID=()): + def previous(self, _ID=()) -> Any: + """Retrieve the previously stored value at `_ID` without recomputing. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID for which to retrieve the previous value. + + Returns + ------- + Any + The previously stored value if `_ID` is valid. + Returns `[]` if `_ID` is not a valid index. + + """ + if self.data.valid_index(_ID): return self.data[_ID].current_value() else: return [] - def recurse_children(self, memory=set()): + def recurse_children(self, memory=None) -> Set['DeepTrackNode']: + """Return all subchildren of this node. + + Parameters + ---------- + memory : set, optional + Memory set to track visited nodes (not used directly here). + + Returns + ------- + set + All nodes in the subtree rooted at this node, including itself. + """ + + # Simply return `_all_subchildren` since it's maintained incrementally. return self._all_subchildren - def old_recurse_children(self, memory=None): - # On first call, instantiate memory + def old_recurse_children(self, memory=None) -> Set['DeepTrackNode']: + """Legacy recursive method for traversing children. + + Parameters + ---------- + memory : list, optional + A list to remember visited nodes, ensuring that each node is + yielded only once. + + Yields + ------ + DeepTrackNode + Yields each node in a depth-first traversal. + + Notes + ----- + This method is kept for backward compatibility or debugging purposes. + + """ + + # On first call, instantiate memory. if memory is None: memory = [] - # Make sure each DeepTrackNode is only yielded once + # Make sure each DeepTrackNode is only yielded once. if self in memory: return - # Remember self + # Remember self. memory.append(self) - # Yield self and recurse children + # Yield self and recurse children. yield self + # Recursively traverse children. for child in self.children: yield from child.recurse_children(memory=memory) - def recurse_dependencies(self, memory=None): - # On first call, instantiate memory + def recurse_dependencies(self, memory=None) -> Iterator['DeepTrackNode']: + """Yield all dependencies of this node, ensuring each is visited once. + + Parameters + ---------- + memory : list, optional + A list of visited nodes to avoid repeated visits or infinite loops. + + Yields + ------ + DeepTrackNode + Yields this node and all nodes it depends on. + + """ + + # On first call, instantiate memory. if memory is None: memory = [] - # Make sure each DeepTrackNode is only yielded once + # Make sure each DeepTrackNode is only yielded once. if self in memory: return - # Remember self + # Remember self. memory.append(self) - # Yield self and recurse dependencies + # Yield self and recurse dependencies. yield self + # Recursively yield dependencies. for dependency in self.dependencies: yield from dependency.recurse_dependencies(memory=memory) - def get_citations(self): - """Get citations for all objects in a pipeline.""" + def get_citations(self) -> Set[str]: + """Get citations from this node and all its dependencies. + + Gathers citations from this node and all nodes that it depends on. + Citations are stored as a class attribute `citations`. + + Returns + ------- + set + Set of all citations relevant to this node and its dependency tree. + + """ # Initialize citations as a set of elements from self.citations. citations = set(self.citations) if self.citations else set() @@ -608,32 +951,94 @@ def get_citations(self): return citations - def __call__(self, _ID=()): + def __call__(self, _ID=()) -> Any: + """Evaluate this node at `_ID`. + + If the data at `_ID` is valid, it returns the stored value. Otherwise, + it calls `action` to compute a new value, stores it, and returns it. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID at which to evaluate the node’s action. + + Returns + ------- + Any + The computed or retrieved data for the given `_ID`. + + """ if self.is_valid(_ID): try: return self.current_value(_ID) except KeyError: - pass + pass # Data might have been invalidated or removed. + # Call action with or without `_ID` depending on `_accepts_ID`. if self._accepts_ID: new_value = self.action(_ID=_ID) else: new_value = self.action() + # Store the newly computed value. self.store(new_value, _ID=_ID) + return self.current_value(_ID) - def current_value(self, _ID=()): + def current_value(self, _ID=()) -> Any: + """Retrieve the currently stored value at `_ID`. + + Parameters + ---------- + _ID : Tuple[int, ...], optional + The ID at which to retrieve the current value. + + Returns + ------- + Any + The currently stored value for `_ID`. + + """ + return self.data[_ID].current_value() - def __hash__(self): + def __hash__(self) -> int: + """Return a unique hash for this node. + + Uses the node’s `id` to ensure uniqueness. + + """ + return id(self) - def __getitem__(self, idx): + def __getitem__(self, idx) -> 'DeepTrackNode': + """Allow indexing into the node’s computed data. + + Parameters + ---------- + idx : Any + The index applied to the result of evaluating this node. + + Returns + ------- + DeepTrackNode + A new node that, when evaluated, applies `idx` to the result of + `self`. + + Notes + ----- + This effectively creates a node that corresponds to `self(...)[idx]`, + allowing you to select parts of the computed data dynamically. + """ + + # Create a new node whose action indexes into this node’s result. node = DeepTrackNode(lambda _ID=None: self(_ID=_ID)[idx]) + node.add_dependency(self) + self.add_child(node) + return node # Node-node operators. @@ -788,7 +1193,6 @@ def __rge__(self, other): return _create_node_with_operator(operator.__ge__, other, self) - def _equivalent(a, b): """Check if two objects are equivalent (internal function). From 73858c021266aeaa233b454d1768c70dc4576fc5 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:18:07 +0100 Subject: [PATCH 044/105] Update core.py --- deeptrack/backend/core.py | 79 ++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 774cc7e6f..c069c610c 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -7,63 +7,66 @@ Main Features ------------- -1. **Data Management**: - - `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, validate, and manage data with dependency tracking. - - Enables nested structures and flexible indexing for complex data hierarchies. - -2. **Computational Graphs**: - - `DeepTrackNode` forms the backbone of computation pipelines, representing nodes in a computation graph. - - Nodes support lazy evaluation, dependency tracking, and caching to optimize performance. - - Implements mathematical operators for easy composition of computational graphs. - -3. **Citations**: - - Supports citing the relevant publication (`Midtvedt et al., 2021`) to ensure proper attribution. - -4. **Utilities**: - - Includes helper functions like `_equivalent` and `_create_node_with_operator` to streamline graph operations. +1. Data Management: + - `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, + validate, and manage data with dependency tracking. + - Enables nested structures and flexible indexing for complex data + hierarchies. + +2. Computational Graphs: + - `DeepTrackNode` forms the backbone of computation pipelines, representing + nodes in a computation graph. + - Nodes support lazy evaluation, dependency tracking, and caching to + optimize performance. + - Implements mathematical operators for easy composition of computational + graphs. + +3. Citations: + - Supports citing the relevant publication (`Midtvedt et al., 2021`) to + ensure proper attribution. + +4. Utilities: + - Includes helper functions like `_equivalent` and + `_create_node_with_operator` to streamline graph operations. Package Structure ----------------- -- **Data Containers**: +- Data Containers: - `DeepTrackDataObject`: A basic container for data with validation status. - - `DeepTrackDataDict`: Stores multiple data objects indexed by unique access IDs, enabling nested data storage. - -- **Computation Nodes**: - - `DeepTrackNode`: Represents a node in a computation graph, capable of lazy evaluation, caching, and dependency management. + - `DeepTrackDataDict`: Stores multiple data objects indexed by unique access + IDs, enabling nested data storage. -- **Citation Management**: - - Provides support for including citations in pipelines for academic and scientific use. +- Computation Nodes: + - `DeepTrackNode`: Represents a node in a computation graph, capable of lazy + evaluation, caching, and dependency management. -- **Utilities**: - - Functions for equivalence checking and operator-based node creation simplify working with computation graphs. - -Dependencies ------------- -- `numpy`: Provides efficient numerical operations. -- `operator`: Enables operator overloading for computation nodes. -- `weakref.WeakSet`: Manages relationships between nodes without creating circular dependencies. +- Citation Management: + - Provides support for including citations in pipelines for academic and + scientific use. Usage ----- -This package is the core component of the DeepTrack framework. It enables users to: +This package is the core component of the DeepTrack2 framework. It enables to: - Construct flexible and efficient computational pipelines. - Manage data and dependencies in a hierarchical structure. - Perform lazy evaluations for performance optimization. Example ------- -```python -# Create a DeepTrackNode with an action -node = DeepTrackNode(lambda x: x**2) -node.store(5) +Create a DeepTrackNode with an action: + +>>> node = DeepTrackNode(lambda x: x**2) +>>> node.store(5) + +Retrieve the stored value: -# Retrieve the stored value -print(node.current_value()) # Output: 25 +>>> print(node.current_value()) # Output: 25 """ -import operator -from weakref import WeakSet +import operator # Operator overloading for computation nodes. +from weakref import WeakSet # Manages relationships between nodes without + # creating circular dependencies. import numpy as np from typing import Any, Dict, Iterator, Optional, Set, Tuple, Union From 62a566729e9a748b0c229ad07ec1599fe5d46047 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:29:47 +0100 Subject: [PATCH 045/105] Update core.py --- deeptrack/backend/core.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index c069c610c..bbd01c71b 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -179,8 +179,8 @@ class DeepTrackDataDict: (the access ID). This is particularly useful for handling sequences of data or nested structures, as required by features like `Repeat`. - The default access ID is an empty tuple `()`. The length of the IDs stored - must be consistent once an entry is created. If an ID longer than the + The default access ID is an empty tuple `()`. Once an entry is created, all + IDs must match the established key length. If an ID longer than the stored length is requested, the request is trimmed. If an ID shorter than what is stored is requested, a dictionary slice containing all matching entries is returned. This mechanism supports flexible indexing of nested @@ -221,16 +221,18 @@ class DeepTrackDataDict: Marks all stored data objects as invalid. validate() Marks all stored data objects as valid. - valid_index(_ID : tuple) -> bool + valid_index(_ID : Tuple[int, ...]) -> bool Checks if the given ID is valid for the current configuration. - create_index(_ID : tuple = ()) + create_index(_ID : Tuple[int, ...] = ()) Creates an entry for the given ID if it does not exist. - __getitem__(_ID : tuple) -> DeepTrackDataObject' - | Dict[Tuple[int, ...], 'DeepTrackDataObject'] + __getitem__(_ID : tuple) -> Union[ + DeepTrackDataObject, + Dict[Tuple[int, ...], DeepTrackDataObject] + ] Retrieves data associated with the ID. Can return a `DeepTrackDataObject` or a dict of matching entries if `_ID` is shorter than `keylength`. - __contains__(_ID : tuple) -> bool + __contains__(_ID : Tuple[int, ...]) -> bool Checks if the given ID exists in the dictionary. """ @@ -374,8 +376,8 @@ def create_index(self, _ID: Tuple[int, ...] = ()) -> None: def __getitem__( self, _ID: Tuple[int, ...], - ) -> Union['DeepTrackDataObject', - Dict[Tuple[int, ...], 'DeepTrackDataObject']]: + ) -> Union[DeepTrackDataObject, + Dict[Tuple[int, ...], DeepTrackDataObject]]: """Retrieve data associated with a given ID. Parameters From 052b16acdcd197a9962448f59f3242fb099a3eef Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:50:17 +0100 Subject: [PATCH 046/105] Update core.py --- deeptrack/backend/core.py | 161 ++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 87 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index bbd01c71b..8b00c8b7d 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -69,7 +69,9 @@ # creating circular dependencies. import numpy as np -from typing import Any, Dict, Iterator, Optional, Set, Tuple, Union +from typing import ( + Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Union +) from .. import utils @@ -442,100 +444,79 @@ class DeepTrackNode: This class represents a node within a computation graph, where each node can store data and compute new values based on its dependencies. The value - of a node is computed by calling its `action` method, which can depend on - the data stored in this node or in other nodes (dependencies). - - Key Features - ------------- - - Lazy Evaluation: - The node’s value is only computed when needed and cached, avoiding - unnecessary recomputations. - - Dependency Tracking: - Nodes keep track of their dependencies and children, enabling - hierarchical and iterative computations. - - ID-Based Indexing: - Data can be stored and retrieved using `_ID` tuples, allowing for - nested and structured indexing of data. - - Citations: - Each node can contribute references (citations), making research - reproducibility and attribution more straightforward. + of a node is computed by calling its `action` method. Attributes ---------- data : DeepTrackDataDict - A dictionary-like object for storing data, indexed by tuples of - integers. + A dictionary-like object for storing data, indexed by tuples of ints. children : WeakSet[DeepTrackNode] - A set of nodes that depend on this node. Changing this node may affect - its children. + Set of nodes that depend on this node. dependencies : WeakSet[DeepTrackNode] - A set of nodes on which this node depends. If any dependency changes, - the validity of this node’s data may be affected. + Set of nodes on which this node depends. _action : Callable - Function or lambda defining how to compute new values for this node. - If `_accepts_ID` is `True`, `action` is called with `_ID` as parameter. + The function or lambda to compute new values. _accepts_ID : bool - Indicates whether the `action` function accepts an `_ID` parameter. - _all_subchildren : set - Set of all nodes in the subtree rooted at this node, including itself. - - Methods + Whether `action` accepts `_ID`. + _all_subchildren : Set[DeepTrackNode] + All nodes in the subtree rooted at this node, including itself. + citations : List[str] + Citations associated with this node. + + Methods ------- - action : Callable - The node’s computation function. When set, checks if `_ID` is accepted. + action : property + Get/set the computation function. add_child(other: DeepTrackNode) -> DeepTrackNode - Adds a `DeepTrackNode` as a child of this node. + Adds a child node. add_dependency(other: DeepTrackNode) -> DeepTrackNode - Adds a `DeepTrackNode` as a dependency of this node. + Adds a dependency node. store(data: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode - Stores computed data associated with this node. + Stores computed data. is_valid(_ID: Tuple[int, ...] = ()) -> bool - Checks if data for the given `_ID` is currently valid. + Checks if data is valid. valid_index(_ID: Tuple[int, ...]) -> bool - Checks if `_ID` is a valid index for this node’s data. + Checks if `_ID` is valid. invalidate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode - Marks this node’s data (and that of its children) as invalid. + Invalidates this node’s and its children's data. validate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode - Marks this node’s data (and that of its children) as valid. + Validates this node’s and its children's data. _update() -> DeepTrackNode - Resets data for all children of all dependencies, often after a change. + Internal method to reset data. set_value(value: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode - Sets a value for this node’s data, invalidating first if needed. + Sets a value, invalidating if necessary. previous(_ID: Tuple[int, ...] = ()) -> Any - Retrieves the previously stored value for the given `_ID`. - recurse_children(memory: Set['DeepTrackNode'] = set()) - -> Set['DeepTrackNode'] - Returns all subchildren of this node. Used for dependency traversal. - old_recurse_children(memory: Optional[List['DeepTrackNode']] = None) - -> Iterator['DeepTrackNode'] - A legacy method that yields nodes in a depth-first manner. - recurse_dependencies(memory: Optional[List['DeepTrackNode']] = None) - -> Iterator['DeepTrackNode'] - Yields all dependencies of this node, ensuring each node is visited - only once. + Returns previously stored value. + recurse_children(memory: Optional[Set[DeepTrackNode]] = None) + -> Set[DeepTrackNode] + Returns all subchildren. + old_recurse_children(memory: Optional[List[DeepTrackNode]] = None) + -> Iterator[DeepTrackNode] + Legacy depth-first traversal. + recurse_dependencies(memory: Optional[List[DeepTrackNode]] = None) + -> Iterator[DeepTrackNode] + Yields dependencies. get_citations() -> Set[str] - Gathers citations from this node and all its dependencies. + Gathers citations. __call__(_ID: Tuple[int, ...] = ()) -> Any - Evaluates the node by calling `action` and stores/retrieves the result. + Evaluates the node. current_value(_ID: Tuple[int, ...] = ()) -> Any - Retrieves the currently stored value for `_ID`. + Returns currently stored value. __hash__() -> int - Returns a unique hash for this node based on its `id`. + Returns unique hash. __getitem__(idx: Any) -> DeepTrackNode - Allows indexing into the result of this node, returning a new node that - applies indexing to the computed data. + Index into the node’s computed data. """ # A unique sentinel object for default action. __none_like_default = object() - # Citations associated with this DeepTrack2. citations = [citation_Midtvet2021Quantitative] @property - def action(self): + def action(self) -> Callable[..., Any]: """Callable: The function that computes this node’s value. When accessed, returns the current action. This is often a lambda or @@ -547,12 +528,12 @@ def action(self): return self._action @action.setter - def action(self, value): + def action(self, value: Callable[..., Any]) -> None: """Set the action used to compute this node’s value. Parameters ---------- - value : Callable + value : Callable[..., Any] A function or lambda to be used for computing the node’s value. If the function’s signature includes `_ID`, this node will pass `_ID` when calling `action`. @@ -560,15 +541,13 @@ def action(self, value): self._action = value self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") - def __init__(self, action=__none_like_default, **kwargs): + def __init__(self, action: Any =__none_like_default, **kwargs: Any): """Initialize a new DeepTrackNode. Parameters ---------- - action : Callable or object, optional - The action used to compute this node’s value. If not provided or if - __none_like_default is used, defaults to a lambda that does - nothing. + action : Callable or Any, optional + Action to compute this node’s value. If not provided, uses a no-op. **kwargs : dict Additional arguments for subclasses or extended functionality. @@ -589,8 +568,7 @@ def __init__(self, action=__none_like_default, **kwargs): self.action = lambda: action # Check if action accepts `_ID`. - self._accepts_ID = \ - utils.get_kwarg_names(self.action).__contains__("_ID") + self._accepts_ID = "_ID" in utils.get_kwarg_names(self.action) # Call super init in case of multiple inheritance. super().__init__(**kwargs) @@ -599,7 +577,7 @@ def __init__(self, action=__none_like_default, **kwargs): self._all_subchildren = set() self._all_subchildren.add(self) - def add_child(self, other) -> 'DeepTrackNode': + def add_child(self, other: 'DeepTrackNode') -> 'DeepTrackNode': """Add a child node, indicating that `other` depends on this node. Parameters @@ -621,7 +599,7 @@ def add_child(self, other) -> 'DeepTrackNode': """ self.children.add(other) - if not self in other.dependencies: + if self not in other.dependencies: other.add_dependency(self) # Ensure bidirectional relationship. # Get all subchildren of `other` and add `other` itself. @@ -636,8 +614,8 @@ def add_child(self, other) -> 'DeepTrackNode': return self - def add_dependency(self, other) -> 'DeepTrackNode': - """Add a dependency to this node. + def add_dependency(self, other: 'DeepTrackNode') -> 'DeepTrackNode': + """Add a dependency node indicating this node depends on `other`. Parameters ---------- @@ -657,7 +635,7 @@ def add_dependency(self, other) -> 'DeepTrackNode': return self - def store(self, data, _ID=()) -> 'DeepTrackNode': + def store(self, data: Any, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': """Store computed data in this node. Parameters @@ -680,7 +658,7 @@ def store(self, data, _ID=()) -> 'DeepTrackNode': return self - def is_valid(self, _ID=()) -> bool: + def is_valid(self, _ID: Tuple[int, ...] = ()) -> bool: """Check if data for the given ID is valid. Parameters @@ -700,7 +678,7 @@ def is_valid(self, _ID=()) -> bool: except (KeyError, AttributeError): return False - def valid_index(self, _ID) ->bool: + def valid_index(self, _ID: Tuple[int, ...]) -> bool: """Check if `_ID` is a valid index for this node’s data. Parameters @@ -717,7 +695,7 @@ def valid_index(self, _ID) ->bool: return self.data.valid_index(_ID) - def invalidate(self, _ID=()) -> bool: + def invalidate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': """Mark this node’s data and all its children’s data as invalid. Parameters @@ -739,7 +717,7 @@ def invalidate(self, _ID=()) -> bool: return self - def validate(self, _ID=()) -> 'DeepTrackNode': + def validate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': """Mark this node’s data and all its children’s data as valid. Parameters @@ -789,7 +767,7 @@ def _update(self) -> 'DeepTrackNode': return self - def set_value(self, value, _ID=()) -> 'DeepTrackNode': + def set_value(self, value, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': """Set a value for this node’s data at `_ID`. If the value is different from the currently stored one (or if it is @@ -819,7 +797,7 @@ def set_value(self, value, _ID=()) -> 'DeepTrackNode': return self - def previous(self, _ID=()) -> Any: + def previous(self, _ID: Tuple[int, ...] = ()) -> Any: """Retrieve the previously stored value at `_ID` without recomputing. Parameters @@ -840,7 +818,10 @@ def previous(self, _ID=()) -> Any: else: return [] - def recurse_children(self, memory=None) -> Set['DeepTrackNode']: + def recurse_children( + self, + memory: Optional[Set['DeepTrackNode']] = None, + ) -> Set['DeepTrackNode']: """Return all subchildren of this node. Parameters @@ -857,7 +838,10 @@ def recurse_children(self, memory=None) -> Set['DeepTrackNode']: # Simply return `_all_subchildren` since it's maintained incrementally. return self._all_subchildren - def old_recurse_children(self, memory=None) -> Set['DeepTrackNode']: + def old_recurse_children( + self, + memory: Optional[List['DeepTrackNode']] = None, + ) -> Iterator['DeepTrackNode']: """Legacy recursive method for traversing children. Parameters @@ -895,7 +879,10 @@ def old_recurse_children(self, memory=None) -> Set['DeepTrackNode']: for child in self.children: yield from child.recurse_children(memory=memory) - def recurse_dependencies(self, memory=None) -> Iterator['DeepTrackNode']: + def recurse_dependencies( + self, + memory: Optional[List['DeepTrackNode']] = None, + ) -> Iterator['DeepTrackNode']: """Yield all dependencies of this node, ensuring each is visited once. Parameters @@ -956,7 +943,7 @@ def get_citations(self) -> Set[str]: return citations - def __call__(self, _ID=()) -> Any: + def __call__(self, _ID: Tuple[int, ...] = ()) -> Any: """Evaluate this node at `_ID`. If the data at `_ID` is valid, it returns the stored value. Otherwise, @@ -991,7 +978,7 @@ def __call__(self, _ID=()) -> Any: return self.current_value(_ID) - def current_value(self, _ID=()) -> Any: + def current_value(self, _ID: Tuple[int, ...] = ()) -> Any: """Retrieve the currently stored value at `_ID`. Parameters @@ -1017,7 +1004,7 @@ def __hash__(self) -> int: return id(self) - def __getitem__(self, idx) -> 'DeepTrackNode': + def __getitem__(self, idx: Any) -> 'DeepTrackNode': """Allow indexing into the node’s computed data. Parameters From d209b31f2c8fcc97203dc86b798046093a03d723 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 09:52:27 +0100 Subject: [PATCH 047/105] Update core.py --- deeptrack/backend/core.py | 79 +++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 8b00c8b7d..6ad4317a3 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -5,51 +5,50 @@ to support building flexible pipelines for scientific data analysis and machine learning applications. +This package is the core component of the DeepTrack2 framework. It enables +users to: +- Construct flexible and efficient computational pipelines. +- Manage data and dependencies in a hierarchical structure. +- Perform lazy evaluations for performance optimization. + Main Features ------------- -1. Data Management: - - `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, - validate, and manage data with dependency tracking. - - Enables nested structures and flexible indexing for complex data - hierarchies. - -2. Computational Graphs: - - `DeepTrackNode` forms the backbone of computation pipelines, representing - nodes in a computation graph. - - Nodes support lazy evaluation, dependency tracking, and caching to - optimize performance. - - Implements mathematical operators for easy composition of computational - graphs. - -3. Citations: - - Supports citing the relevant publication (`Midtvedt et al., 2021`) to - ensure proper attribution. - -4. Utilities: - - Includes helper functions like `_equivalent` and - `_create_node_with_operator` to streamline graph operations. +Data Management: +- `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, + validate, and manage data with dependency tracking. +- Enables nested structures and flexible indexing for complex data + hierarchies. + +Computational Graphs: +- `DeepTrackNode` forms the backbone of computation pipelines, representing + nodes in a computation graph. +- Nodes support lazy evaluation, dependency tracking, and caching to + optimize performance. +- Implements mathematical operators for easy composition of computational + graphs. + +Citations: +- Supports citing the relevant publication (`Midtvedt et al., 2021`) to + ensure proper attribution. + +Utilities: +- Includes helper functions like `_equivalent` and + `_create_node_with_operator` to streamline graph operations. Package Structure ----------------- -- Data Containers: - - `DeepTrackDataObject`: A basic container for data with validation status. - - `DeepTrackDataDict`: Stores multiple data objects indexed by unique access - IDs, enabling nested data storage. - -- Computation Nodes: - - `DeepTrackNode`: Represents a node in a computation graph, capable of lazy - evaluation, caching, and dependency management. - -- Citation Management: - - Provides support for including citations in pipelines for academic and - scientific use. - -Usage ------ -This package is the core component of the DeepTrack2 framework. It enables to: -- Construct flexible and efficient computational pipelines. -- Manage data and dependencies in a hierarchical structure. -- Perform lazy evaluations for performance optimization. +Data Containers: +- `DeepTrackDataObject`: A basic container for data with validation status. +- `DeepTrackDataDict`: Stores multiple data objects indexed by unique access + IDs, enabling nested data storage. + +Computation Nodes: +- `DeepTrackNode`: Represents a node in a computation graph, capable of lazy + evaluation, caching, and dependency management. + +Citation Management: +- Provides support for including citations in pipelines for academic and + scientific use. Example ------- From 093c2e3c2a95242c7e94f856cdcff1698dfb5509 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:04:51 +0100 Subject: [PATCH 048/105] u --- deeptrack/backend/core.py | 6 +++--- deeptrack/features.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 6ad4317a3..71bd48b66 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -509,7 +509,7 @@ class DeepTrackNode: """ # A unique sentinel object for default action. - __none_like_default = object() + __nonelike_default = object() # Citations associated with this DeepTrack2. citations = [citation_Midtvet2021Quantitative] @@ -540,7 +540,7 @@ def action(self, value: Callable[..., Any]) -> None: self._action = value self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") - def __init__(self, action: Any =__none_like_default, **kwargs: Any): + def __init__(self, action: Any =__nonelike_default, **kwargs: Any): """Initialize a new DeepTrackNode. Parameters @@ -560,7 +560,7 @@ def __init__(self, action: Any =__none_like_default, **kwargs: Any): # If action is provided, set it. If it's callable, use it directly; # otherwise, wrap it in a lambda. - if action is not self.__none_like_default: + if action is not self.__nonelike_default: if callable(action): self.action = action else: diff --git a/deeptrack/features.py b/deeptrack/features.py index d60f0822c..bd3691e3f 100644 --- a/deeptrack/features.py +++ b/deeptrack/features.py @@ -92,7 +92,7 @@ class Feature(DeepTrackNode): # A None-safe default value to compare against - __none_like_default = object() + __nonelike_default = object() _wrap_array_with_image = False From 75c1f9a5556ccaa5ca2053559c4153124a9fa271 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:08:33 +0100 Subject: [PATCH 049/105] Update core.py --- deeptrack/backend/core.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 71bd48b66..7f49e306f 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -508,9 +508,6 @@ class DeepTrackNode: """ - # A unique sentinel object for default action. - __nonelike_default = object() - # Citations associated with this DeepTrack2. citations = [citation_Midtvet2021Quantitative] @@ -540,7 +537,11 @@ def action(self, value: Callable[..., Any]) -> None: self._action = value self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") - def __init__(self, action: Any =__nonelike_default, **kwargs: Any): + def __init__( + self, + action: Optional[Callable[..., Any]] = None, + **kwargs: Any, + ): """Initialize a new DeepTrackNode. Parameters @@ -560,7 +561,7 @@ def __init__(self, action: Any =__nonelike_default, **kwargs: Any): # If action is provided, set it. If it's callable, use it directly; # otherwise, wrap it in a lambda. - if action is not self.__nonelike_default: + if action is not None: if callable(action): self.action = action else: From 48ea0e0956578202e970ddf64ea051dae1385ecf Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:14:06 +0100 Subject: [PATCH 050/105] Update core.py --- deeptrack/backend/core.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 7f49e306f..6e26bd6d6 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -508,8 +508,16 @@ class DeepTrackNode: """ + # Attributes. + data: DeepTrackDataDict + children: WeakSet['DeepTrackNode'] + dependencies: WeakSet['DeepTrackNode'] + _action: Callable[..., Any] + _accepts_ID: bool + _all_subchildren: Set['DeepTrackNode'] + # Citations associated with this DeepTrack2. - citations = [citation_Midtvet2021Quantitative] + citations: List[str] = [citation_Midtvet2021Quantitative] @property def action(self) -> Callable[..., Any]: From a3047f27462bf3549a14c6a9e294ba2f822e6d9c Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:24:08 +0100 Subject: [PATCH 051/105] Update core.py --- deeptrack/backend/core.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 6e26bd6d6..58bd38ee6 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1262,12 +1262,18 @@ def _create_node_with_operator(op, a, b): """ # Ensure `a` is a `DeepTrackNode`. Wrap it if necessary. - if not isinstance(a, DeepTrackNode): + if not isinstance(a, DeepTrackNode) and callable(a): a = DeepTrackNode(a) + else: + raise TypeError("Operand 'a' must be callable or a DeepTrackNode, " + + f"got {type(a).__name__}.") # Ensure `b` is a `DeepTrackNode`. Wrap it if necessary. - if not isinstance(b, DeepTrackNode): + if not isinstance(b, DeepTrackNode) and callable(a): b = DeepTrackNode(b) + else: + raise TypeError("Operand 'b' must be callable or a DeepTrackNode, " + + f"got {type(b).__name__}.") # New node that applies the operator `op` to the outputs of `a` and `b`. new_node = DeepTrackNode(lambda _ID=(): op(a(_ID=_ID), b(_ID=_ID))) From 19f06a9042882a1387873721a5f8302f97960c3a Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:36:36 +0100 Subject: [PATCH 052/105] Update core.py --- deeptrack/backend/core.py | 376 +++++++++++++++++++++++++++++++------- 1 file changed, 311 insertions(+), 65 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 58bd38ee6..312d6aba0 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1048,148 +1048,394 @@ def __getitem__(self, idx: Any) -> 'DeepTrackNode': # and `other`. The operators are applied lazily and will be computed only # when the resulting node is evaluated. - def __add__(self, other): - """Add node to other node or value. + def __add__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Add node to another node or value. + + Creates a new `DeepTrackNode` representing the addition of the values + produced by this node (`self`) and another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to add. + + Returns + ------- + DeepTrackNode + A new node that represents the addition operation (`self + other`). - Operation performed: - result = self + other """ + return _create_node_with_operator(operator.__add__, self, other) - def __radd__(self, other): + def __radd__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Add other value to node (right-hand). + + Creates a new `DeepTrackNode` representing the addition of another + node or value (`other`) to the value produced by this node (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to add. + + Returns + ------- + DeepTrackNode + A new node that represents the addition operation (`other + self`). - Operation performed: - result = other + self """ + return _create_node_with_operator(operator.__add__, other, self) - def __sub__(self, other): - """Subtract other node or value from node. + def __sub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Subtract another node or value from node. + + Creates a new `DeepTrackNode` representing the subtraction of the + values produced by another node or value (`other`) from this node + (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to subtract. + + Returns + ------- + DeepTrackNode + A new node that represents the subtraction operation + (`self - other`). - Operation performed: - result = self - other """ + return _create_node_with_operator(operator.__sub__, self, other) - def __rsub__(self, other): + def __rsub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Subtract node from other value (right-hand). + + Creates a new `DeepTrackNode` representing the subtraction of the value + produced by this node (`self`) from another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to subtract from. + + Returns + ------- + DeepTrackNode + A new node that represents the subtraction operation + `other - self`). - Operation performed: - result = other - self """ + return _create_node_with_operator(operator.__sub__, other, self) - def __mul__(self, other): - """Multiply node by other node or value. + def __mul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Multiply node by another node or value. + + Creates a new `DeepTrackNode` representing the multiplication of the + values produced by this node (`self`) and another node or value + (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to multiply by. + + Returns + ------- + DeepTrackNode + A new node that represents the multiplication operation + (`self * other`). - Operation performed: - result = self * other """ + return _create_node_with_operator(operator.__mul__, self, other) - def __rmul__(self, other): + def __rmul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Multiply other value by node (right-hand). - - Operation performed: - result = other * self + + Creates a new `DeepTrackNode` representing the multiplication of + another node or value (`other`) by the value produced by this node + (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to multiply. + + Returns + ------- + DeepTrackNode + A new node that represents the multiplication operation + (`other * self`). """ return _create_node_with_operator(operator.__mul__, other, self) - def __truediv__(self, other): - """Divide node by other node or value. + def __truediv__( + self, + other: Union['DeepTrackNode', Any], + ) -> 'DeepTrackNode': + """Divide node by another node or value. + + Creates a new `DeepTrackNode` representing the division of the value + produced by this node (`self`) by another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to divide by. + + Returns + ------- + DeepTrackNode + A new node that represents the division operation (`self / other`). - Operation performed: - result = self / other """ + return _create_node_with_operator(operator.__truediv__, self, other) - def __rtruediv__(self, other): + def __rtruediv__( + self, + other: Union['DeepTrackNode', Any], + ) -> 'DeepTrackNode': """Divide other value by node (right-hand). + + Creates a new `DeepTrackNode` representing the division of another + node or value (`other`) by the value produced by this node (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to divide. + + Returns + ------- + DeepTrackNode + A new node that represents the division operation (`other / self`). - Operation performed: - result = other / self """ + return _create_node_with_operator(operator.__truediv__, other, self) - def __floordiv__(self, other): - """Perform floor division of node by other node or value. + def __floordiv__( + self, + other: Union['DeepTrackNode', Any], + ) -> 'DeepTrackNode': + """Perform floor division of node by another node or value. + + Creates a new `DeepTrackNode` representing the floor division of the + value produced by this node (`self`) by another node or value + (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to divide by. + + Returns + ------- + DeepTrackNode + A new node that represents the floor division operation + (`self // other`). - Operation performed: - result = self // other """ + return _create_node_with_operator(operator.__floordiv__, self, other) - def __rfloordiv__(self, other): + def __rfloordiv__( + self, + other: Union['DeepTrackNode', Any], + ) -> 'DeepTrackNode': """Perform floor division of other value by node (right-hand). + + Creates a new `DeepTrackNode` representing the floor division of + another node or value (`other`) by the value produced by this node + (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to divide. + + Returns + ------- + DeepTrackNode + A new node that represents the floor division operation + (`other // self`). - Operation performed: - result = other // self """ + return _create_node_with_operator(operator.__floordiv__, other, self) - def __lt__(self, other): - """Check if node is less than other node or value. + def __lt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Check if node is less than another node or value. + + Creates a new `DeepTrackNode` representing the comparison of this node + (`self`) being less than another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to compare with. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation (`self < other`). - Operation performed: - result = self < other """ + return _create_node_with_operator(operator.__lt__, self, other) - def __rlt__(self, other): + def __rlt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Check if other value is less than node (right-hand). + + Creates a new `DeepTrackNode` representing the comparison of another + node or value (`other`) being less than this node (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to compare. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`other < self`). - Operation performed: - result = other < self """ + return _create_node_with_operator(operator.__lt__, other, self) - def __gt__(self, other): - """Check if node is greater than other node or value. + def __gt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Check if node is greater than another node or value. + + Creates a new `DeepTrackNode` representing the comparison of this node + (`self`) being greater than another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to compare with. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`self > other`). - Operation performed: - result = self > other """ + return _create_node_with_operator(operator.__gt__, self, other) - def __rgt__(self, other): + def __rgt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Check if other value is greater than node (right-hand). + + Creates a new `DeepTrackNode` representing the comparison of another + node or value (`other`) being greater than this node (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to compare. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`other > self`). - Operation performed: - result = other > self """ + return _create_node_with_operator(operator.__gt__, other, self) - def __le__(self, other): - """Check if node is less than or equal to other node or value. + def __le__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Check if node is less than or equal to another node or value. + + Creates a new `DeepTrackNode` representing the comparison of this node + (`self`) being less than or equal to another node or value (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to compare with. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`self <= other`). - Operation performed: - result = self <= other """ + return _create_node_with_operator(operator.__le__, self, other) - def __rle__(self, other): + def __rle__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Check if other value is less than or equal to node (right-hand). + + Creates a new `DeepTrackNode` representing the comparison of another + node or value (`other`) being less than or equal to this node (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to compare. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`other <= self`). - Operation performed: - result = other <= self """ + return _create_node_with_operator(operator.__le__, other, self) - def __ge__(self, other): - """Check if node is greater than or equal to other node or value. + def __ge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': + """Check if node is greater than or equal to another node or value. + + Creates a new `DeepTrackNode` representing the comparison of this node + (`self`) being greater than or equal to another node or value + (`other`). + + Parameters + ---------- + other : DeepTrackNode or Any + The node or value to compare with. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`self >= other`). - Operation performed: - result = self >= other """ + return _create_node_with_operator(operator.__ge__, self, other) - def __rge__(self, other): + def __rge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': """Check if other value is greater than or equal to node (right-hand). + + Creates a new `DeepTrackNode` representing the comparison of another + node or value (`other`) being greater than or equal to this node + (`self`). + + Parameters + ---------- + other : DeepTrackNode or Any + The value or node to compare. + + Returns + ------- + DeepTrackNode + A new node that represents the comparison operation + (`other >= self`). - Operation performed: - result = other >= self """ + return _create_node_with_operator(operator.__ge__, other, self) @@ -1269,7 +1515,7 @@ def _create_node_with_operator(op, a, b): + f"got {type(a).__name__}.") # Ensure `b` is a `DeepTrackNode`. Wrap it if necessary. - if not isinstance(b, DeepTrackNode) and callable(a): + if not isinstance(b, DeepTrackNode) and callable(b): b = DeepTrackNode(b) else: raise TypeError("Operand 'b' must be callable or a DeepTrackNode, " From a90d95ee466d546e0a6c23d71e738b367bc55e5c Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 10:40:42 +0100 Subject: [PATCH 053/105] Update core.py --- deeptrack/backend/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 312d6aba0..a5424b9b8 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -510,8 +510,10 @@ class DeepTrackNode: # Attributes. data: DeepTrackDataDict - children: WeakSet['DeepTrackNode'] - dependencies: WeakSet['DeepTrackNode'] + children: WeakSet #TODO + # From Python 3.9, change to WeakSet['DeepTrackNode'] + dependencies: WeakSet #TODO + # From Python 3.9, change to WeakSet['DeepTrackNode'] _action: Callable[..., Any] _accepts_ID: bool _all_subchildren: Set['DeepTrackNode'] From cd3f250aef82f4839f3ee97616fc0d38671833dc Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:10:08 +0100 Subject: [PATCH 054/105] Create core_test.py --- deeptrack/test/backend/core_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 deeptrack/test/backend/core_test.py diff --git a/deeptrack/test/backend/core_test.py b/deeptrack/test/backend/core_test.py new file mode 100644 index 000000000..e69de29bb From 23b37efbb5c81557198b9d59910c94aadcfeba9a Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:14:12 +0100 Subject: [PATCH 055/105] Update core_test.py --- deeptrack/test/backend/core_test.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deeptrack/test/backend/core_test.py b/deeptrack/test/backend/core_test.py index e69de29bb..57a99b421 100644 --- a/deeptrack/test/backend/core_test.py +++ b/deeptrack/test/backend/core_test.py @@ -0,0 +1,14 @@ +import unittest + +from deeptrack.backend.core import DeepTrackDataObject +from deeptrack.backend.core import DeepTrackDataDict +from deeptrack.backend.core import DeepTrackNode + + +class TestCore(unittest.TestCase): + + pass + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 762fcf573ff1c47bc530199b5a4ba4782d344710 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:17:49 +0100 Subject: [PATCH 056/105] Update core_test.py --- deeptrack/test/backend/core_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deeptrack/test/backend/core_test.py b/deeptrack/test/backend/core_test.py index 57a99b421..044ce9c34 100644 --- a/deeptrack/test/backend/core_test.py +++ b/deeptrack/test/backend/core_test.py @@ -7,7 +7,8 @@ class TestCore(unittest.TestCase): - pass + def test_trial(self): + self.assetTrue(1 == 1) if __name__ == "__main__": From 4ab4a5ee04bf28479b37fbe7be5f405904584608 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:19:33 +0100 Subject: [PATCH 057/105] u --- deeptrack/test/backend/{core_test.py => test_core.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deeptrack/test/backend/{core_test.py => test_core.py} (100%) diff --git a/deeptrack/test/backend/core_test.py b/deeptrack/test/backend/test_core.py similarity index 100% rename from deeptrack/test/backend/core_test.py rename to deeptrack/test/backend/test_core.py From f78d32e54ab9f1cdc9804e7415e32a529967569a Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:20:39 +0100 Subject: [PATCH 058/105] Create __init__.py --- deeptrack/test/backend/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 deeptrack/test/backend/__init__.py diff --git a/deeptrack/test/backend/__init__.py b/deeptrack/test/backend/__init__.py new file mode 100644 index 000000000..e69de29bb From 07d873e622a88bb0c0ee54f8c906590f4e3dbb48 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:24:19 +0100 Subject: [PATCH 059/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 044ce9c34..3260ee374 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -6,10 +6,10 @@ class TestCore(unittest.TestCase): - + def test_trial(self): - self.assetTrue(1 == 1) + self.assertTrue(1 == 1) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From b9272369ad9310be1ce65a9982fa3bced57549dc Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:43:20 +0100 Subject: [PATCH 060/105] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7e7302b6b..f998beecb 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="deeptrack", - version="2.0.0rc0", + version="2.0.0", license="MIT", packages=find_packages(), author=( From dcb70e676a21739ec5a8a3fc8cbf83396ad66179 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:43:22 +0100 Subject: [PATCH 061/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 3260ee374..ac33342b0 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -1,3 +1,6 @@ +# import sys +# sys.path.append(".") # Adds the module to path. + import unittest from deeptrack.backend.core import DeepTrackDataObject From ad271fd89b455a2043009e3c6eb979a7a0f1434f Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:44:22 +0100 Subject: [PATCH 062/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index ac33342b0..6039a1f34 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -1,3 +1,4 @@ +# Use this only when running the test locally. # import sys # sys.path.append(".") # Adds the module to path. From a61267bd2fed911ee752696ff1814336b6548442 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:46:30 +0100 Subject: [PATCH 063/105] u --- .github/workflows/{python-app.yml => ci.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{python-app.yml => ci.yml} (97%) diff --git a/.github/workflows/python-app.yml b/.github/workflows/ci.yml similarity index 97% rename from .github/workflows/python-app.yml rename to .github/workflows/ci.yml index b02a0032f..4e297ea9a 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/ci.yml @@ -43,4 +43,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with unittest run: | - python -m unittest deeptrack.test + python -m unittest From 2d98a8dcbb692c332c312e890b573138304a2350 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:50:20 +0100 Subject: [PATCH 064/105] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e297ea9a..b02a0032f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,4 +43,4 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with unittest run: | - python -m unittest + python -m unittest deeptrack.test From 7370ada4441369a9861c050d284c1653e0895e52 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 15:52:11 +0100 Subject: [PATCH 065/105] Update __init__.py --- deeptrack/test/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deeptrack/test/__init__.py b/deeptrack/test/__init__.py index 07578d9d9..c1fddba90 100644 --- a/deeptrack/test/__init__.py +++ b/deeptrack/test/__init__.py @@ -1,3 +1,5 @@ +from .backend.test_core import * + from .test_aberrations import * from .test_augmentations import * from .test_elementwise import * From 81d089703126a36824e1bebaa436aa500505e25c Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 16:08:28 +0100 Subject: [PATCH 066/105] Update test_utils.py --- deeptrack/test/test_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index d45c7508f..61bb3f0cc 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -1,3 +1,7 @@ +# Use this only when running the test locally. +# import sys +# sys.path.append(".") # Adds the module to path. + import unittest from .. import utils From fad0c3551ab4b490a757f0a6cc7926eef12acf50 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 16:08:43 +0100 Subject: [PATCH 067/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 6039a1f34..0aa0bc01e 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -4,9 +4,7 @@ import unittest -from deeptrack.backend.core import DeepTrackDataObject -from deeptrack.backend.core import DeepTrackDataDict -from deeptrack.backend.core import DeepTrackNode +from deeptrack.backend import core class TestCore(unittest.TestCase): From b24ff8fbf1f992f7104dfc0bdc87021122c962f4 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 16:48:10 +0100 Subject: [PATCH 068/105] Update __init__.py --- deeptrack/test/backend/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/deeptrack/test/backend/__init__.py b/deeptrack/test/backend/__init__.py index e69de29bb..d25beb5a6 100644 --- a/deeptrack/test/backend/__init__.py +++ b/deeptrack/test/backend/__init__.py @@ -0,0 +1 @@ +from .test_core import * \ No newline at end of file From 06b08c732ac8a48d8aee60264d72abb368929419 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 16:48:13 +0100 Subject: [PATCH 069/105] Update __init__.py --- deeptrack/test/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deeptrack/test/__init__.py b/deeptrack/test/__init__.py index c1fddba90..a4bdf38b8 100644 --- a/deeptrack/test/__init__.py +++ b/deeptrack/test/__init__.py @@ -1,4 +1,4 @@ -from .backend.test_core import * +from .backend import * from .test_aberrations import * from .test_augmentations import * From 9a46bd10fc0f21634e7afd2e17fd685b817640dd Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sat, 7 Dec 2024 17:35:20 +0100 Subject: [PATCH 070/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 0aa0bc01e..f06c29077 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -1,3 +1,7 @@ +# pylint: disable=C0115:missing-class-docstring +# pylint: disable=C0116:missing-function-docstring +# pylint: disable=C0103:invalid-name + # Use this only when running the test locally. # import sys # sys.path.append(".") # Adds the module to path. @@ -9,8 +13,19 @@ class TestCore(unittest.TestCase): - def test_trial(self): - self.assertTrue(1 == 1) + def test_DeepTrackDataObject(self): + dataobj = core.DeepTrackDataObject() + dataobj.store(1) + self.assertEqual(dataobj.current_value(), 1) + self.assertEqual(dataobj.is_valid(), True) + + dataobj.invalidate() + self.assertEqual(dataobj.current_value(), 1) + self.assertEqual(dataobj.is_valid(), False) + + dataobj.validate() + self.assertEqual(dataobj.current_value(), 1) + self.assertEqual(dataobj.is_valid(), True) if __name__ == "__main__": From 865f6c92bcb7951f5fb379dabe793f041c0daeab Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 07:17:13 +0100 Subject: [PATCH 071/105] Update core.py --- deeptrack/backend/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index a5424b9b8..f3d836b15 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -75,7 +75,7 @@ from .. import utils -citation_Midtvet2021Quantitative = """ +citation_midtvet2021quantitative = """ @article{Midtvet2021Quantitative, author = {Midtvedt, Benjamin and Helgadottir, Saga and Argun, Aykut and Pineda, Jesús and Midtvedt, Daniel and Volpe, Giovanni}, @@ -519,7 +519,7 @@ class DeepTrackNode: _all_subchildren: Set['DeepTrackNode'] # Citations associated with this DeepTrack2. - citations: List[str] = [citation_Midtvet2021Quantitative] + citations: List[str] = [citation_midtvet2021quantitative] @property def action(self) -> Callable[..., Any]: From c39d1f4030758a1b69e59854f62f7f202631e413 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 07:49:10 +0100 Subject: [PATCH 072/105] Create trial.ipynb --- deeptrack/trial.ipynb | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 deeptrack/trial.ipynb diff --git a/deeptrack/trial.ipynb b/deeptrack/trial.ipynb new file mode 100644 index 000000000..cb7db2c10 --- /dev/null +++ b/deeptrack/trial.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from deeptrack.backend import core\n", + "\n", + "\n", + "dataset = core.DeepTrackDataDict()\n", + "\n", + "dataset.create_index((0,))\n", + "dataset[(0,)].store({\"image\": [1, 2, 3], \"label\": 0})\n", + "\n", + "dataset.create_index((1,))\n", + "dataset[(1,)].store({\"image\": [4, 5, 6], \"label\": 1})\n", + "\n", + "dataset[(0,)].invalidate()\n", + "\n", + "dataset[(1,)].validate()\n", + "\n", + "dataset[(0,)].is_valid()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_values([, ])" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dataset.dict.values()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "py_env_dlcc", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 50b701c511cf69e6c886e3237eec2ea2a59a84ca Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 07:49:23 +0100 Subject: [PATCH 073/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index f06c29077..63230a475 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -15,18 +15,88 @@ class TestCore(unittest.TestCase): def test_DeepTrackDataObject(self): dataobj = core.DeepTrackDataObject() + + # Test storing and validating data. dataobj.store(1) self.assertEqual(dataobj.current_value(), 1) self.assertEqual(dataobj.is_valid(), True) + # Test invalidating data. dataobj.invalidate() self.assertEqual(dataobj.current_value(), 1) self.assertEqual(dataobj.is_valid(), False) + # Test validating data. dataobj.validate() self.assertEqual(dataobj.current_value(), 1) self.assertEqual(dataobj.is_valid(), True) + def test_DeepTrackDataDict(self): + dataset = core.DeepTrackDataDict() + + # Test initial state. + self.assertEqual(dataset.keylength, None) + self.assertFalse(dataset.dict) + + # Create indices and store data. + dataset.create_index((0,)) + dataset[(0,)].store({"image": [1, 2, 3], "label": 0}) + + dataset.create_index((1,)) + dataset[(1,)].store({"image": [4, 5, 6], "label": 1}) + + self.assertEqual(dataset.keylength, 1) + self.assertEqual(len(dataset.dict), 2) + self.assertIn((0,), dataset.dict) + self.assertIn((1,), dataset.dict) + + # Test retrieving stored data. + self.assertEqual(dataset[(0,)].current_value(), + {"image": [1, 2, 3], "label": 0}) + self.assertEqual(dataset[(1,)].current_value(), + {"image": [4, 5, 6], "label": 1}) + + # Test validation and invalidation - all. + self.assertTrue(dataset[(0,)].is_valid()) + self.assertTrue(dataset[(1,)].is_valid()) + + dataset.invalidate() + self.assertFalse(dataset[(0,)].is_valid()) + self.assertFalse(dataset[(1,)].is_valid()) + + dataset.validate() + self.assertTrue(dataset[(0,)].is_valid()) + self.assertTrue(dataset[(1,)].is_valid()) + + # Test validation and invalidation - single node. + self.assertTrue(dataset[(0,)].is_valid()) + + dataset[(0,)].invalidate() + self.assertFalse(dataset[(0,)].is_valid()) + self.assertTrue(dataset[(1,)].is_valid()) + + dataset[(1,)].invalidate() + self.assertFalse(dataset[(0,)].is_valid()) + self.assertFalse(dataset[(1,)].is_valid()) + + dataset[(0,)].validate() + self.assertTrue(dataset[(0,)].is_valid()) + self.assertFalse(dataset[(1,)].is_valid()) + + dataset[(1,)].validate() + self.assertTrue(dataset[(0,)].is_valid()) + self.assertTrue(dataset[(1,)].is_valid()) + + # Test iteration over entries. + for key, value in dataset.dict.items(): + self.assertIn(key, {(0,), (1,)}) + self.assertIsInstance(value, core.DeepTrackDataObject) + + + def test_DeepTrackNode(self): + pass + + if __name__ == "__main__": unittest.main() From 1f245e0375f32a5e73da9a340ffca1120813f2ad Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 07:50:03 +0100 Subject: [PATCH 074/105] Delete trial.ipynb --- deeptrack/trial.ipynb | 87 ------------------------------------------- 1 file changed, 87 deletions(-) delete mode 100644 deeptrack/trial.ipynb diff --git a/deeptrack/trial.ipynb b/deeptrack/trial.ipynb deleted file mode 100644 index cb7db2c10..000000000 --- a/deeptrack/trial.ipynb +++ /dev/null @@ -1,87 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from deeptrack.backend import core\n", - "\n", - "\n", - "dataset = core.DeepTrackDataDict()\n", - "\n", - "dataset.create_index((0,))\n", - "dataset[(0,)].store({\"image\": [1, 2, 3], \"label\": 0})\n", - "\n", - "dataset.create_index((1,))\n", - "dataset[(1,)].store({\"image\": [4, 5, 6], \"label\": 1})\n", - "\n", - "dataset[(0,)].invalidate()\n", - "\n", - "dataset[(1,)].validate()\n", - "\n", - "dataset[(0,)].is_valid()" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "dict_values([, ])" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dataset.dict.values()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "py_env_dlcc", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 242058f05c73ca0ca16833dbcc90853e85df6ea4 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 08:09:56 +0100 Subject: [PATCH 075/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 63230a475..90ac6f66d 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -94,8 +94,28 @@ def test_DeepTrackDataDict(self): self.assertIsInstance(value, core.DeepTrackDataObject) - def test_DeepTrackNode(self): - pass + def test_DeepTrackNode_basics(self): + node = core.DeepTrackNode(action=lambda: 42) + + # Evaluate the node. + result = node() # Value is calculated and stored. + self.assertEqual(result, 42) + + # Store a value. + node.store(100) # Value is stored. + self.assertEqual(node.current_value(), 100) + self.assertTrue(node.is_valid()) + + # Invalidate the node and check the value. + node.invalidate() + self.assertFalse(node.is_valid()) + + self.assertEqual(node.current_value(), 100) # Value is retrieved. + self.assertFalse(node.is_valid()) + + self.assertEqual(node(), 42) # Value is calculated and stored. + self.assertTrue(node.is_valid()) + if __name__ == "__main__": From 7846058ce14f29a560e989c069cda5ac318dc83e Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 09:06:00 +0100 Subject: [PATCH 076/105] Update core.py --- deeptrack/backend/core.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index f3d836b15..369783601 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1510,18 +1510,20 @@ def _create_node_with_operator(op, a, b): """ # Ensure `a` is a `DeepTrackNode`. Wrap it if necessary. - if not isinstance(a, DeepTrackNode) and callable(a): - a = DeepTrackNode(a) - else: - raise TypeError("Operand 'a' must be callable or a DeepTrackNode, " - + f"got {type(a).__name__}.") + if not isinstance(a, DeepTrackNode): + if callable(a): + a = DeepTrackNode(a) + else: + raise TypeError("Operand 'a' must be callable or a DeepTrackNode, " + + f"got {type(a).__name__}.") # Ensure `b` is a `DeepTrackNode`. Wrap it if necessary. - if not isinstance(b, DeepTrackNode) and callable(b): - b = DeepTrackNode(b) - else: - raise TypeError("Operand 'b' must be callable or a DeepTrackNode, " - + f"got {type(b).__name__}.") + if not isinstance(b, DeepTrackNode): + if callable(b): + b = DeepTrackNode(b) + else: + raise TypeError("Operand 'b' must be callable or a DeepTrackNode, " + + f"got {type(b).__name__}.") # New node that applies the operator `op` to the outputs of `a` and `b`. new_node = DeepTrackNode(lambda _ID=(): op(a(_ID=_ID), b(_ID=_ID))) From db80b4145d3625b6de42846c1e12e03deb7fb107 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 11:31:19 +0100 Subject: [PATCH 077/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 90ac6f66d..50c150c05 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -117,6 +117,39 @@ def test_DeepTrackNode_basics(self): self.assertTrue(node.is_valid()) + def test_DeepTrackNode_dependencies(self): + parent = core.DeepTrackNode(action=lambda: 10) + child = core.DeepTrackNode(action=lambda _ID=None: parent() * 2) + parent.add_child(child) # Establish dependency. + + # Check that the just create nodes are invalid as not calculated. + self.assertFalse(parent.is_valid()) + self.assertFalse(child.is_valid()) + + # Calculate child, and therefore parent. + result = child() + self.assertEqual(result, 20) + self.assertTrue(parent.is_valid()) + self.assertTrue(child.is_valid()) + + # Invalidate parent and check child validity. + parent.invalidate() + self.assertFalse(parent.is_valid()) + self.assertFalse(child.is_valid()) + + # Validate parent and ensure child is invalid until recomputation. + parent.validate() + self.assertTrue(parent.is_valid()) + self.assertFalse(child.is_valid()) + + # Recompute child and check its validity + child() + self.assertTrue(parent.is_valid()) + self.assertTrue(child.is_valid()) + + + def test_DeepTrackNode_dependencies(self): + pass if __name__ == "__main__": unittest.main() From ecfeba311bd647b2e6a4b5260cd588c2b5380b32 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 11:46:52 +0100 Subject: [PATCH 078/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 50c150c05..30de30a83 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -140,7 +140,7 @@ def test_DeepTrackNode_dependencies(self): # Validate parent and ensure child is invalid until recomputation. parent.validate() self.assertTrue(parent.is_valid()) - self.assertFalse(child.is_valid()) + self.assertFalse(child.is_valid()) ###TODO this test doesn't pass! # Recompute child and check its validity child() @@ -148,7 +148,7 @@ def test_DeepTrackNode_dependencies(self): self.assertTrue(child.is_valid()) - def test_DeepTrackNode_dependencies(self): + def test_DeepTrackNode_overloading(self): pass if __name__ == "__main__": From 30fa5ecec979227cc9a433e64cd8eb64d079e4c8 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:07:35 +0100 Subject: [PATCH 079/105] Updated the DeepTrackNode.validate method not to revalidate children --- deeptrack/backend/core.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 369783601..db2740fb8 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -728,7 +728,7 @@ def invalidate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': return self def validate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': - """Mark this node’s data and all its children’s data as valid. + """Mark this node’s data as valid. Parameters ---------- @@ -739,17 +739,9 @@ def validate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': ------- self : DeepTrackNode - Notes - ----- - If a child does not have the specified `_ID`, it is ignored. - """ - for child in self.recurse_children(): - try: - child.data[_ID].validate() - except KeyError: - pass + self.data[_ID].validate() return self From 8aaef94d4f025dfbad4f30509d9c7533e165a4c2 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:07:39 +0100 Subject: [PATCH 080/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 30de30a83..77eb6f480 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -149,7 +149,20 @@ def test_DeepTrackNode_dependencies(self): def test_DeepTrackNode_overloading(self): - pass + node1 = core.DeepTrackNode(action=lambda: 5) + node2 = core.DeepTrackNode(action=lambda: 10) + + sum_node = node1 + node2 + self.assertEqual(sum_node(), 15) + + diff_node = node2 - node1 + self.assertEqual(diff_node(), 5) + + prod_node = node1 * node2 + self.assertEqual(prod_node(), 50) + + div_node = node2 / node1 + self.assertEqual(div_node(), 2) if __name__ == "__main__": unittest.main() From 49ddb7f862dbfa7ede29a08a96f2685331727146 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:10:28 +0100 Subject: [PATCH 081/105] u --- deeptrack/backend/core.py | 2 +- deeptrack/test/backend/test_core.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index db2740fb8..d7408d7a6 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -479,7 +479,7 @@ class DeepTrackNode: invalidate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode Invalidates this node’s and its children's data. validate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode - Validates this node’s and its children's data. + Validates this node’s data. _update() -> DeepTrackNode Internal method to reset data. set_value(value: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 77eb6f480..695dd1da6 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -140,7 +140,7 @@ def test_DeepTrackNode_dependencies(self): # Validate parent and ensure child is invalid until recomputation. parent.validate() self.assertTrue(parent.is_valid()) - self.assertFalse(child.is_valid()) ###TODO this test doesn't pass! + self.assertFalse(child.is_valid()) # Recompute child and check its validity child() From dd8c15bebe64fdfd9e28c4fb67ed404a7772b8fa Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:22:42 +0100 Subject: [PATCH 082/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 695dd1da6..ff9b0fe72 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -164,5 +164,11 @@ def test_DeepTrackNode_overloading(self): div_node = node2 / node1 self.assertEqual(div_node(), 2) + def test_DeepTrackNode_citations(self): + node = core.DeepTrackNode(action=lambda: 42) + citations = node.get_citations() + self.assertIn(core.citation_midtvet2021quantitative, citations) + + if __name__ == "__main__": unittest.main() From 60009ef9c8bdbbfda879d2ecdeab29024768af12 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:34:35 +0100 Subject: [PATCH 083/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index ff9b0fe72..198510967 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -147,6 +147,23 @@ def test_DeepTrackNode_dependencies(self): self.assertTrue(parent.is_valid()) self.assertTrue(child.is_valid()) + def test_DeepTrackNode_nested_dependencies(self): + parent = core.DeepTrackNode(action=lambda: 5) + middle = core.DeepTrackNode(action=lambda: parent() + 5) + child = core.DeepTrackNode(action=lambda: middle() * 2) + + parent.add_child(middle) + middle.add_child(child) + + result = child() + self.assertEqual(result, 20, "Nested computation failed.") + + # Invalidate the middle and check propagation. + middle.invalidate() + self.assertTrue(parent.is_valid()) + self.assertFalse(middle.is_valid()) + self.assertFalse(child.is_valid()) + def test_DeepTrackNode_overloading(self): node1 = core.DeepTrackNode(action=lambda: 5) @@ -164,11 +181,12 @@ def test_DeepTrackNode_overloading(self): div_node = node2 / node1 self.assertEqual(div_node(), 2) + def test_DeepTrackNode_citations(self): node = core.DeepTrackNode(action=lambda: 42) citations = node.get_citations() self.assertIn(core.citation_midtvet2021quantitative, citations) - + if __name__ == "__main__": unittest.main() From e15b958da5419e8d2b9cf1b1b52fd6a37fa61d49 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:55:17 +0100 Subject: [PATCH 084/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 198510967..534008637 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -186,6 +186,20 @@ def test_DeepTrackNode_citations(self): node = core.DeepTrackNode(action=lambda: 42) citations = node.get_citations() self.assertIn(core.citation_midtvet2021quantitative, citations) + + def test_DeepTrackNode_single_id(self): + """Test a single _ID on a simple parent-child relationship.""" + + parent = core.DeepTrackNode(action=lambda: 10) + child = core.DeepTrackNode(action=lambda _ID=None: parent(_ID) * 2) + parent.add_child(child) + + # Store value for a specific _ID + parent.store(15, _ID=(0,)) + child_value = child(_ID=(0,)) + + self.assertEqual(child_value, 30) + self.assertEqual(parent.previous((0,)), 15) if __name__ == "__main__": From e087cddda2bdf6a0295b0feac7f122a561db974e Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 12:57:49 +0100 Subject: [PATCH 085/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 534008637..7d13d297a 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -187,6 +187,7 @@ def test_DeepTrackNode_citations(self): citations = node.get_citations() self.assertIn(core.citation_midtvet2021quantitative, citations) + def test_DeepTrackNode_single_id(self): """Test a single _ID on a simple parent-child relationship.""" @@ -194,13 +195,17 @@ def test_DeepTrackNode_single_id(self): child = core.DeepTrackNode(action=lambda _ID=None: parent(_ID) * 2) parent.add_child(child) - # Store value for a specific _ID - parent.store(15, _ID=(0,)) - child_value = child(_ID=(0,)) + # Store value for a specific _ID's. + for id, value in enumerate(range(10)): + parent.store(id, _ID=(id,)) + + for id, value in enumerate(range(10)): + self.assertEqual(child(_ID=(id,)), value * 2) + self.assertEqual(parent.previous((id,)), value) + + + - self.assertEqual(child_value, 30) - self.assertEqual(parent.previous((0,)), 15) - if __name__ == "__main__": unittest.main() From 43ae6641930898ba078e66ed9e8feb51c7ef4237 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 15:25:17 +0100 Subject: [PATCH 086/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 7d13d297a..b94ba636a 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -199,11 +199,50 @@ def test_DeepTrackNode_single_id(self): for id, value in enumerate(range(10)): parent.store(id, _ID=(id,)) + # Retrieves the values stored in children and parents. for id, value in enumerate(range(10)): self.assertEqual(child(_ID=(id,)), value * 2) self.assertEqual(parent.previous((id,)), value) + def test_DeepTrackNode_nested_ids(self): + """Test nested IDs for parent-child relationships.""" + parent = core.DeepTrackNode(action=lambda: 10) + child = core.DeepTrackNode( + action=lambda _ID=None: parent(_ID[:1]) * _ID[1] + ) + parent.add_child(child) + + # Store values for parent at different IDs. + parent.store(5, _ID=(0,)) + parent.store(10, _ID=(1,)) + + # Compute child values for nested IDs + child_value_0_0 = child(_ID=(0, 0)) # Uses parent(_ID=(0,)). + self.assertEqual(child_value_0_0, 0) + + child_value_0_1 = child(_ID=(0, 1)) # Uses parent(_ID=(0,)). + self.assertEqual(child_value_0_1, 5) + + child_value_1_0 = child(_ID=(1, 0)) # Uses parent(_ID=(1,)). + self.assertEqual(child_value_1_0, 0) + + child_value_1_1 = child(_ID=(1, 1)) # Uses parent(_ID=(1,)). + self.assertEqual(child_value_1_1, 10) + + + def test_DeepTrackNode_replicated_behavior(self): + """Test replicated behavior where IDs expand.""" + + particle = core.DeepTrackNode(action=lambda _ID=None: _ID[0] + 1) + + # Replicate node logic. + cluster = core.DeepTrackNode( + action=lambda _ID=None: particle(_ID=(0,)) + particle(_ID=(1,)) + ) + + cluster_value = cluster() + self.assertEqual(cluster_value, 3) From 3b9970b1423f8905769753ea2cb9868f95c25975 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 15:54:58 +0100 Subject: [PATCH 087/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 60 +++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index b94ba636a..9f1ac6cfc 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -244,6 +244,66 @@ def test_DeepTrackNode_replicated_behavior(self): cluster_value = cluster() self.assertEqual(cluster_value, 3) + def test_DeepTrackNode_parent_id_inheritance(self): + + # Children with IDs matching than parents. + parent_matching = core.DeepTrackNode(action=lambda: 10) + child_matching = core.DeepTrackNode( + action=lambda _ID=None: parent_matching(_ID[:1]) * 2 + ) + parent_matching.add_child(child_matching) + + parent_matching.store(7, _ID=(0,)) + parent_matching.store(5, _ID=(1,)) + + self.assertEqual(child_matching(_ID=(0,)), 14) + self.assertEqual(child_matching(_ID=(1,)), 10) + + # Children with IDs deeper than parents. + parent_deeper = core.DeepTrackNode(action=lambda: 10) + child_deeper = core.DeepTrackNode( + action=lambda _ID=None: parent_deeper(_ID[:1]) * 2 + ) + parent_deeper.add_child(child_deeper) + + parent_deeper.store(7, _ID=(0,)) + parent_deeper.store(5, _ID=(1,)) + + self.assertEqual(child_deeper(_ID=(0, 0)), 14) + self.assertEqual(child_deeper(_ID=(0, 1)), 14) + self.assertEqual(child_deeper(_ID=(0, 2)), 14) + + self.assertEqual(child_deeper(_ID=(1, 0)), 10) + self.assertEqual(child_deeper(_ID=(1, 1)), 10) + self.assertEqual(child_deeper(_ID=(1, 2)), 10) + + def test_DeepTrackNode_invalidation_and_ids(self): + """Test that invalidating a parent affects specific IDs of children.""" + + parent = core.DeepTrackNode(action=lambda: 10) + child = core.DeepTrackNode(action=lambda _ID=None: parent(_ID[:1]) * 2) + parent.add_child(child) + + # Store and compute values. + parent.store(0, _ID=(0,)) + parent.store(1, _ID=(1,)) + child(_ID=(0, 0)) + child(_ID=(0, 1)) + child(_ID=(1, 0)) + child(_ID=(1, 1)) + + # Invalidate the parent at _ID=(0,). + parent.invalidate((0,)) + + self.assertFalse(parent.is_valid((0,))) + self.assertFalse(parent.is_valid((1,))) + self.assertFalse(child.is_valid((0, 0))) + self.assertFalse(child.is_valid((0, 1))) + self.assertFalse(child.is_valid((1, 0))) + self.assertFalse(child.is_valid((1, 1))) + + + if __name__ == "__main__": From 74bd095ffd9ba5b471b71fc2c532617025384522 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 15:59:03 +0100 Subject: [PATCH 088/105] Update core.py --- deeptrack/backend/core.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index d7408d7a6..63e1d8c2d 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -717,6 +717,11 @@ def invalidate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': Returns ------- self : DeepTrackNode + + Note + ---- + At the moment, the code to invalidate specific IDs is not implemented, + so the _ID parameter is not used. """ From 640cb297f7a5fc7281563b2e222fba82b9a9ebf0 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 16:05:56 +0100 Subject: [PATCH 089/105] Update test_core.py --- deeptrack/test/backend/test_core.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/deeptrack/test/backend/test_core.py b/deeptrack/test/backend/test_core.py index 9f1ac6cfc..4521d097d 100644 --- a/deeptrack/test/backend/test_core.py +++ b/deeptrack/test/backend/test_core.py @@ -303,7 +303,27 @@ def test_DeepTrackNode_invalidation_and_ids(self): self.assertFalse(child.is_valid((1, 1))) + def test_DeepTrackNode_dependency_graph_with_ids(self): + """Test a multi-level dependency graph with nested IDs.""" + A = core.DeepTrackNode(action=lambda: 10) + B = core.DeepTrackNode(action=lambda _ID=None: A(_ID[:-1]) + 5) + C = core.DeepTrackNode( + action=lambda _ID=None: B(_ID[:-1]) * (_ID[-1] + 1) + ) + A.add_child(B) + B.add_child(C) + + # Store values for A at different IDs. + A.store(3, _ID=(0,)) + A.store(4, _ID=(1,)) + + # Compute values for C at nested IDs. + C_0_1_2 = C(_ID=(0, 1, 2)) # B((0, 1)) * (2 + 1) + # (A((0,)) + 5) * (2 + 1) + # (3 + 5) * (2 + 1) + # 24 + self.assertEqual(C_0_1_2, 24) if __name__ == "__main__": From f4ed240c1d232bb21ef6cadb9359356e2d4ef59a Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 17:15:28 +0100 Subject: [PATCH 090/105] Update core.py --- deeptrack/backend/core.py | 364 ++++++++++++++++++++------------------ 1 file changed, 194 insertions(+), 170 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 63e1d8c2d..d509d2d18 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1,58 +1,42 @@ -"""DeepTrack2 core package. +"""Core data strDeepTrack2 package. -This package provides the core classes and functionality required for managing, -processing, and evaluating data within the DeepTrack framework. It is designed -to support building flexible pipelines for scientific data analysis and machine -learning applications. - -This package is the core component of the DeepTrack2 framework. It enables -users to: +This package provides the core DeepTrack2 classes to manage and process data. +In particular, it enables users to: - Construct flexible and efficient computational pipelines. - Manage data and dependencies in a hierarchical structure. - Perform lazy evaluations for performance optimization. Main Features ------------- -Data Management: -- `DeepTrackDataObject` and `DeepTrackDataDict` provide tools to store, - validate, and manage data with dependency tracking. -- Enables nested structures and flexible indexing for complex data - hierarchies. - -Computational Graphs: -- `DeepTrackNode` forms the backbone of computation pipelines, representing - nodes in a computation graph. -- Nodes support lazy evaluation, dependency tracking, and caching to - optimize performance. -- Implements mathematical operators for easy composition of computational - graphs. - -Citations: -- Supports citing the relevant publication (`Midtvedt et al., 2021`) to - ensure proper attribution. - -Utilities: -- Includes helper functions like `_equivalent` and - `_create_node_with_operator` to streamline graph operations. +Data Management: `DeepTrackDataObject` and `DeepTrackDataDict` provide tools +to store, validate, and manage data with dependency tracking. They enable +nested data structures and flexible indexing for complex data hierarchies. + +Computational Graphs: `DeepTrackNode` forms the backbone of DeepTrack2 +computation pipelines, representing computation nodes in a computation graph. +Nodes support lazy evaluation, dependency tracking, and caching for improved +computational performance. They implement mathematical operators for easy +composition of computational graphs. + +Citations: Supports citing the relevant publication to ensure proper +attribution (e.g., `Midtvedt et al., 2021`). Package Structure ----------------- Data Containers: - `DeepTrackDataObject`: A basic container for data with validation status. -- `DeepTrackDataDict`: Stores multiple data objects indexed by unique access - IDs, enabling nested data storage. +- `DeepTrackDataDict`: A data contained to store multiple data objects + (DeepTrackDataObject) indexed by unique access IDs + (consisting of tuples of integers), enabling nested data + storage. Computation Nodes: - `DeepTrackNode`: Represents a node in a computation graph, capable of lazy evaluation, caching, and dependency management. -Citation Management: -- Provides support for including citations in pipelines for academic and - scientific use. - Example ------- -Create a DeepTrackNode with an action: +Create a DeepTrackNode: >>> node = DeepTrackNode(lambda x: x**2) >>> node.store(5) @@ -64,10 +48,9 @@ """ import operator # Operator overloading for computation nodes. -from weakref import WeakSet # Manages relationships between nodes without +from weakref import WeakSet # Manages relationships between nodes without # creating circular dependencies. -import numpy as np from typing import ( Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Union ) @@ -93,15 +76,13 @@ class DeepTrackDataObject: """Basic data container for DeepTrack2. - This class serves as a simple container for storing data and managing its - validity. It is designed to track whether the data remains valid, based on - changes in dependencies or other external factors that might invalidate the - data since it was last updated. + `DeepTrackDataObject` is a simple data container to store data and track + its validity. Attributes ---------- data : Any - The stored data. Default is `None`. Can hold any data type. + The stored data. Default is `None`. valid : bool A flag indicating whether the stored data is valid. Default is `False`. @@ -112,11 +93,12 @@ class DeepTrackDataObject: current_value() -> Any Returns the currently stored data. is_valid() -> bool - Checks if the stored data is valid. + Returns whether the stored data is valid. invalidate() Marks the data as invalid. validate() Marks the data as valid. + """ # Attributes. @@ -126,86 +108,75 @@ class DeepTrackDataObject: def __init__(self): """Initialize the container without data. - The `data` attribute is set to `None`, and the `valid` attribute is set - to `False` by default. + The `data` and `valid` attributes are set to their default values + `None` and `False`. + """ + self.data = None self.valid = False def store(self, data: Any) -> None: - """Store data in the container and mark it as valid. + """Store data and mark it as valid. Parameters ---------- data : Any The data to be stored in the container. + """ + self.data = data self.valid = True def current_value(self) -> Any: - """Retrieve the currently stored data. + """Retrieve the stored data. Returns ------- Any The data stored in the container. + """ + return self.data def is_valid(self) -> bool: - """Check if the stored data is valid. + """Return whether the stored data is valid. Returns ------- bool `True` if the data is valid, `False` otherwise. + """ + return self.valid def invalidate(self) -> None: """Mark the stored data as invalid.""" + self.valid = False def validate(self) -> None: """Mark the stored data as valid.""" + self.valid = True class DeepTrackDataDict: - """Stores multiple data objects indexed by a tuple of integers (access ID). + """Stores multiple data objects indexed by a tuple of integers (ID). - This class allows a single object to store multiple `DeepTrackDataObject` - instances concurrently, each associated with a unique tuple of integers - (the access ID). This is particularly useful for handling sequences of data - or nested structures, as required by features like `Repeat`. + `DeepTrackDataDict` can store multiple `DeepTrackDataObject` instances, + each associated with a unique tuple of integers (its ID). This is + particularly useful to handle sequences of data or nested structures. - The default access ID is an empty tuple `()`. Once an entry is created, all - IDs must match the established key length. If an ID longer than the - stored length is requested, the request is trimmed. If an ID shorter than - what is stored is requested, a dictionary slice containing all matching - entries is returned. This mechanism supports flexible indexing of nested - data and ensures that dependencies at various nesting depths can be - correctly handled. + The default ID is an empty tuple, `()`. Once the first entry is created, + all IDs must match the established key length: + - If an ID longer than the set length is requested, it is trimmed. + - If an ID shorter than the set length is requested, a dictionary slice + containing all matching entries is returned. - Example - ------- - Consider the following structure, where `Repeat` is a feature that creates - multiple instances of another feature: - - >>> F = Repeat(Repeat(DummyFeature(prop=np.random.rand), 2), 2) - - Here, `F` contains 2 * 2 = 4 instances of the feature `prop`. - These can be accessed using the IDs: - (0, 0), (0, 1), (1, 0), and (1, 1). - - In this nested structure: - - (0, 0) refers to the first repeat of the outer feature and the first - repeat of the inner feature. - - (0, 1) refers to the first repeat of the outer feature and the second - repeat of the inner feature. - And so forth, resolving nested structures via tuples of indices. - Attributes ---------- keylength : int or None @@ -235,6 +206,42 @@ class DeepTrackDataDict: than `keylength`. __contains__(_ID : Tuple[int, ...]) -> bool Checks if the given ID exists in the dictionary. + + Example + ------- + Imagine to have a structure that generates multiple instances of data: + + >>> data_dict = DeepTrackDataDict() + + # Create two top-level entries + >>> data_dict.create_index((0,)) + >>> data_dict.create_index((1,)) + + # Add nested entries + >>> data_dict.create_index((0, 0)) + >>> data_dict.create_index((0, 1)) + >>> data_dict.create_index((1, 0)) + >>> data_dict.create_index((1, 1)) + + Now, store and access values associated with each ID: + + >>> data_dict[(0, 0)].store("Data at (0, 0)") + >>> data_dict[(0, 1)].store("Data at (0, 1)") + >>> data_dict[(1, 0)].store("Data at (1, 0)") + >>> data_dict[(1, 1)].store("Data at (1, 1)") + + Retrieve values based on their IDs: + + >>> print(data_dict[(0, 0)].current_value()) + Data at (0, 0) + + >>> print(data_dict[(1, 1)].current_value()) + Data at (1, 1) + + If requesting a shorter ID, it returns all matching nested entries: + + >>> print(data_dict[(0,)]) + {(0, 0): , (0, 1): } """ @@ -249,7 +256,7 @@ def __init__(self): indicating no data objects are currently stored. """ - + self.keylength = None self.dict = {} @@ -259,7 +266,7 @@ def invalidate(self) -> None: Calls `invalidate()` on every `DeepTrackDataObject` in the dictionary. """ - + for dataobject in self.dict.values(): dataobject.invalidate() @@ -269,13 +276,18 @@ def validate(self) -> None: Calls `validate()` on every `DeepTrackDataObject` in the dictionary. """ - + for dataobject in self.dict.values(): dataobject.validate() def valid_index(self, _ID: Tuple[int, ...]) -> bool: """Check if a given ID is valid for this data dictionary. + If `keylength` is `None`, any tuple ID is considered valid since no + entries have been created yet. If `_ID` already exists in `dict`, it is + automatically valid. Otherwise, `_ID` must have the same length as + `keylength` to be considered valid. + Parameters ---------- _ID : Tuple[int, ...] @@ -290,23 +302,15 @@ def valid_index(self, _ID: Tuple[int, ...]) -> bool: Raises ------ AssertionError - If `_ID` is not a tuple of integers. The error message includes the - actual `_ID` value and the types of its elements for easier - debugging. - - Notes - ----- - - If `keylength` is `None`, any tuple ID is considered valid since no - entries have been created yet. - - If `_ID` already exists in `dict`, it is automatically valid. - - Otherwise, `_ID` must have the same length as `keylength` to be - considered valid. + If `_ID` is not a tuple of integers. """ - - assert ( - isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) - ), ( + + # Ensure `_ID` is a tuple of integers. + assert isinstance(_ID, tuple), ( + f"Data index {_ID} is not a tuple. Got: {type(_ID).__name__}." + ) + assert all(isinstance(i, int) for i in _ID), ( f"Data index {_ID} is not a tuple of integers. " f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." ) @@ -325,6 +329,13 @@ def valid_index(self, _ID: Tuple[int, ...]) -> bool: def create_index(self, _ID: Tuple[int, ...] = ()) -> None: """Create a new data entry for the given ID if not already existing. + Each newly created index is associated with a new + `DeepTrackDataObject`. If `_ID` is already in `dict`, no new entry is + created. + + If `keylength` is `None`, it is set to the length of `_ID`. Once + established, all subsequently created IDs must have this same length. + Parameters ---------- _ID : Tuple[int, ...], optional @@ -335,50 +346,35 @@ def create_index(self, _ID: Tuple[int, ...] = ()) -> None: Raises ------ AssertionError - - If `_ID` is not a tuple of integers. The error message includes - the value of `_ID` and the types of its elements. - - If `_ID` is not a valid index according to the current - configuration. - - Notes - ----- - - If `keylength` is `None`, it is set to the length of `_ID`. Once - established, all subsequently created IDs must have this same length. - - If `_ID` is already in `dict`, no new entry is created. - - Each newly created index is associated with a fresh - `DeepTrackDataObject`. + - If `_ID` is not a tuple of integers. + - If `_ID` is not valid for the current configuration. """ - - # Ensure `_ID` is a tuple of integers. - assert ( - isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) - ), ( - f"Data index {_ID} is not a tuple of integers. " - f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." + + # Check if the given `_ID` is valid. + # (Also: Ensure `_ID` is a tuple of integers.) + assert self.valid_index(_ID), ( + f"{_ID} is not a valid index for current dictionary configuration." ) # If `_ID` already exists, do nothing. if _ID in self.dict: return - # Check if the given `_ID` is valid. - assert self.valid_index(_ID), ( - f"{_ID} is not a valid index for current dictionary configuration." - ) + # Create a new DeepTrackDataObject for this ID. + self.dict[_ID] = DeepTrackDataObject() # If `keylength` is not set, initialize it with current ID's length. if self.keylength is None: self.keylength = len(_ID) - # Create a new DeepTrackDataObject for this ID. - self.dict[_ID] = DeepTrackDataObject() - def __getitem__( - self, + self, _ID: Tuple[int, ...], - ) -> Union[DeepTrackDataObject, - Dict[Tuple[int, ...], DeepTrackDataObject]]: + ) -> Union[ + DeepTrackDataObject, + Dict[Tuple[int, ...], DeepTrackDataObject] + ]: """Retrieve data associated with a given ID. Parameters @@ -388,7 +384,7 @@ def __getitem__( Returns ------- - DeepTrackDataObject or dict + DeepTrackDataObject or Dict[Tuple[int, ...], DeepTrackDataObject] If `_ID` matches `keylength`, returns the corresponding `DeepTrackDataObject`. If `_ID` is longer than `keylength`, the request is trimmed to @@ -402,25 +398,31 @@ def __getitem__( If `_ID` is not a tuple of integers. KeyError If the dictionary is empty (`keylength` is `None`). + """ - assert ( - isinstance(_ID, tuple) and all(isinstance(i, int) for i in _ID) - ), ( + + # Ensure `_ID` is a tuple of integers. + assert isinstance(_ID, tuple), ( + f"Data index {_ID} is not a tuple. Got: {type(_ID).__name__}." + ) + assert all(isinstance(i, int) for i in _ID), ( f"Data index {_ID} is not a tuple of integers. " f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." ) if self.keylength is None: - raise KeyError("Indexing an empty dict.") + raise KeyError("Attempting to index an empty dict.") + # If ID matches keylength, returns corresponding DeepTrackDataObject. if len(_ID) == self.keylength: return self.dict[_ID] - elif len(_ID) > self.keylength: - # Trim the requested ID to match keylength. + + # If ID longer than keylength, trim the requested ID. + if len(_ID) > self.keylength: return self[_ID[: self.keylength]] - else: - # Return a slice of all items matching the shorter ID prefix. - return {k: v for k, v in self.dict.items() if k[: len(_ID)] == _ID} + + # If ID longer than keylength, return a slice of all matching items. + return {k: v for k, v in self.dict.items() if k[: len(_ID)] == _ID} def __contains__(self, _ID: Tuple[int, ...]) -> bool: """Check if a given ID exists in the dictionary. @@ -434,7 +436,23 @@ def __contains__(self, _ID: Tuple[int, ...]) -> bool: ------- bool `True` if the ID exists, `False` otherwise. + + Raises + ------ + AssertionError + If `_ID` is not a tuple of integers. + """ + + # Ensure `_ID` is a tuple of integers. + assert isinstance(_ID, tuple), ( + f"Data index {_ID} is not a tuple. Got: {type(_ID).__name__}." + ) + assert all(isinstance(i, int) for i in _ID), ( + f"Data index {_ID} is not a tuple of integers. " + f"Got a tuple of types: {[type(i).__name__ for i in _ID]}." + ) + return _ID in self.dict @@ -1439,11 +1457,14 @@ def __rge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': def _equivalent(a, b): - """Check if two objects are equivalent (internal function). + """Check if two objects are equivalent. - This is a basic implementation to determine equivalence between two - objects. Additional cases can be implemented as needed to refine this - behavior. + This internal helper function provides a basic implementation to determine + equivalence between two objects: + - If `a` and `b` are the same object (identity check), they are considered + equivalent. + - If both `a` and `b` are empty lists, they are considered equivalent. + Additional cases can be implemented as needed to refine this behavior. Parameters ---------- @@ -1457,33 +1478,38 @@ def _equivalent(a, b): bool `True` if the objects are equivalent, `False` otherwise. - Notes - ----- - - If `a` and `b` are the same object (identity check), they are considered - equivalent. - - If both `a` and `b` are empty lists, they are considered equivalent. """ - + + # If a and b are the same object, return True. if a is b: return True + # If a and b are empty lists, consider them identical. if isinstance(a, list) and isinstance(b, list): return len(a) == 0 and len(b) == 0 + # Otherwise, return False. return False def _create_node_with_operator(op, a, b): """Create a new computation node using a given operator and operands. - This internal helper function constructs a `DeepTrackNode` that represents - the application of the specified operator to two operands. If the operands + This internal helper function constructs a `DeepTrackNode` obtained from + the application of the specified operator to two operands. If the operands are not already `DeepTrackNode` instances, they are converted to nodes. + This function also establishes bidirectional relationships between the new + node and its operands: + - The new node is added as a child of the operands `a` and `b`. + - The operands `a` and `b` are added as dependencies of the new node. + - The operator `op` is applied lazily, meaning it will be evaluated when + the new node is called, for computational efficiency. + Parameters ---------- op : Callable - The operator function to apply. + The operator function. a : Any First operand. If not a `DeepTrackNode`, it will be wrapped in one. b : Any @@ -1492,27 +1518,23 @@ def _create_node_with_operator(op, a, b): Returns ------- DeepTrackNode - A new `DeepTrackNode` that applies the operator `op` to the values of - nodes `a` and `b`. - - Notes - ----- - - This function establishes bidirectional relationships between the new - node and its operands: - - The new node is added as a child of both `a` and `b`. - - The operands are added as dependencies of the new node. - - The operator `op` is applied lazily, meaning it will be evaluated when - the new node is called. + A new `DeepTrackNode` containing the result of applying the operator + `op` to the values of nodes `a` and `b`. + + Raises + ------ + TypeError + If any of the operand is not a `DeepTrackNode` or a callable. """ - + # Ensure `a` is a `DeepTrackNode`. Wrap it if necessary. if not isinstance(a, DeepTrackNode): if callable(a): a = DeepTrackNode(a) else: raise TypeError("Operand 'a' must be callable or a DeepTrackNode, " - + f"got {type(a).__name__}.") + f"got {type(a).__name__}.") # Ensure `b` is a `DeepTrackNode`. Wrap it if necessary. if not isinstance(b, DeepTrackNode): @@ -1520,17 +1542,19 @@ def _create_node_with_operator(op, a, b): b = DeepTrackNode(b) else: raise TypeError("Operand 'b' must be callable or a DeepTrackNode, " - + f"got {type(b).__name__}.") + f"got {type(b).__name__}.") - # New node that applies the operator `op` to the outputs of `a` and `b`. + # New node that applies the operator `op` to the values of `a` and `b`. new_node = DeepTrackNode(lambda _ID=(): op(a(_ID=_ID), b(_ID=_ID))) - - # Establish dependency relationships between the nodes. - new_node.add_dependency(a) - new_node.add_dependency(b) - + # Set the new node as a child of both `a` and `b`. + # (Also: Establish dependency relationships between the nodes.) a.add_child(new_node) b.add_child(new_node) - return new_node \ No newline at end of file + # Establish dependency relationships between the nodes. + # (Not needed because already done implicitly above.) + # new_node.add_dependency(a) + # new_node.add_dependency(b) + + return new_node From 76210c0bcd765f8146f98f79fb7025b7281f0c01 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 17:18:02 +0100 Subject: [PATCH 091/105] Update core.py --- deeptrack/backend/core.py | 80 +++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index d509d2d18..ec82a0eab 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -548,9 +548,9 @@ def action(self) -> Callable[..., Any]: True. """ - + return self._action - + @action.setter def action(self, value: Callable[..., Any]) -> None: """Set the action used to compute this node’s value. @@ -581,7 +581,7 @@ def __init__( Additional arguments for subclasses or extended functionality. """ - + self.data = DeepTrackDataDict() self.children = WeakSet() self.dependencies = WeakSet() @@ -597,7 +597,7 @@ def __init__( # Check if action accepts `_ID`. self._accepts_ID = "_ID" in utils.get_kwarg_names(self.action) - + # Call super init in case of multiple inheritance. super().__init__(**kwargs) @@ -625,11 +625,11 @@ def add_child(self, other: 'DeepTrackNode') -> 'DeepTrackNode': remain consistent. """ - + self.children.add(other) if self not in other.dependencies: other.add_dependency(self) # Ensure bidirectional relationship. - + # Get all subchildren of `other` and add `other` itself. subchildren = other._all_subchildren.copy() subchildren.add(other) @@ -657,7 +657,7 @@ def add_dependency(self, other: 'DeepTrackNode') -> 'DeepTrackNode': Returns the current node for chaining. """ - + self.dependencies.add(other) other.add_child(self) # Ensure the child relationship is also set. @@ -679,7 +679,7 @@ def store(self, data: Any, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': self : DeepTrackNode """ - + # Create the index if necessary, then store data in it. self.data.create_index(_ID) self.data[_ID].store(data) @@ -700,7 +700,7 @@ def is_valid(self, _ID: Tuple[int, ...] = ()) -> bool: `True` if data at `_ID` is valid, otherwise `False`. """ - + try: return self.data[_ID].is_valid() except (KeyError, AttributeError): @@ -742,7 +742,7 @@ def invalidate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': so the _ID parameter is not used. """ - + # Invalidate data for all children of this node. for child in self.recurse_children(): @@ -763,7 +763,7 @@ def validate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': self : DeepTrackNode """ - + self.data[_ID].validate() return self @@ -810,7 +810,7 @@ def set_value(self, value, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': self : DeepTrackNode """ - + # Check if current value is equivalent. If not, invalidate and store # the new value. If set to same value, no need to invalidate if not ( @@ -837,14 +837,14 @@ def previous(self, _ID: Tuple[int, ...] = ()) -> Any: Returns `[]` if `_ID` is not a valid index. """ - + if self.data.valid_index(_ID): return self.data[_ID].current_value() else: return [] def recurse_children( - self, + self, memory: Optional[Set['DeepTrackNode']] = None, ) -> Set['DeepTrackNode']: """Return all subchildren of this node. @@ -859,12 +859,12 @@ def recurse_children( set All nodes in the subtree rooted at this node, including itself. """ - + # Simply return `_all_subchildren` since it's maintained incrementally. return self._all_subchildren def old_recurse_children( - self, + self, memory: Optional[List['DeepTrackNode']] = None, ) -> Iterator['DeepTrackNode']: """Legacy recursive method for traversing children. @@ -885,7 +885,7 @@ def old_recurse_children( This method is kept for backward compatibility or debugging purposes. """ - + # On first call, instantiate memory. if memory is None: memory = [] @@ -1017,7 +1017,7 @@ def current_value(self, _ID: Tuple[int, ...] = ()) -> Any: The currently stored value for `_ID`. """ - + return self.data[_ID].current_value() def __hash__(self) -> int: @@ -1048,14 +1048,14 @@ def __getitem__(self, idx: Any) -> 'DeepTrackNode': This effectively creates a node that corresponds to `self(...)[idx]`, allowing you to select parts of the computed data dynamically. """ - + # Create a new node whose action indexes into this node’s result. node = DeepTrackNode(lambda _ID=None: self(_ID=_ID)[idx]) - + node.add_dependency(self) - + self.add_child(node) - + return node # Node-node operators. @@ -1082,7 +1082,7 @@ def __add__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': A new node that represents the addition operation (`self + other`). """ - + return _create_node_with_operator(operator.__add__, self, other) def __radd__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1102,7 +1102,7 @@ def __radd__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': A new node that represents the addition operation (`other + self`). """ - + return _create_node_with_operator(operator.__add__, other, self) def __sub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1124,7 +1124,7 @@ def __sub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`self - other`). """ - + return _create_node_with_operator(operator.__sub__, self, other) def __rsub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1145,7 +1145,7 @@ def __rsub__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': `other - self`). """ - + return _create_node_with_operator(operator.__sub__, other, self) def __mul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1167,7 +1167,7 @@ def __mul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`self * other`). """ - + return _create_node_with_operator(operator.__mul__, self, other) def __rmul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1210,7 +1210,7 @@ def __truediv__( A new node that represents the division operation (`self / other`). """ - + return _create_node_with_operator(operator.__truediv__, self, other) def __rtruediv__( @@ -1233,7 +1233,7 @@ def __rtruediv__( A new node that represents the division operation (`other / self`). """ - + return _create_node_with_operator(operator.__truediv__, other, self) def __floordiv__( @@ -1258,7 +1258,7 @@ def __floordiv__( (`self // other`). """ - + return _create_node_with_operator(operator.__floordiv__, self, other) def __rfloordiv__( @@ -1283,7 +1283,7 @@ def __rfloordiv__( (`other // self`). """ - + return _create_node_with_operator(operator.__floordiv__, other, self) def __lt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1303,7 +1303,7 @@ def __lt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': A new node that represents the comparison operation (`self < other`). """ - + return _create_node_with_operator(operator.__lt__, self, other) def __rlt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1324,7 +1324,7 @@ def __rlt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`other < self`). """ - + return _create_node_with_operator(operator.__lt__, other, self) def __gt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1345,7 +1345,7 @@ def __gt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`self > other`). """ - + return _create_node_with_operator(operator.__gt__, self, other) def __rgt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1366,7 +1366,7 @@ def __rgt__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`other > self`). """ - + return _create_node_with_operator(operator.__gt__, other, self) def __le__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1387,7 +1387,7 @@ def __le__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`self <= other`). """ - + return _create_node_with_operator(operator.__le__, self, other) def __rle__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1408,7 +1408,7 @@ def __rle__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`other <= self`). """ - + return _create_node_with_operator(operator.__le__, other, self) def __ge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1428,9 +1428,9 @@ def __ge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': DeepTrackNode A new node that represents the comparison operation (`self >= other`). - + """ - + return _create_node_with_operator(operator.__ge__, self, other) def __rge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': @@ -1452,7 +1452,7 @@ def __rge__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': (`other >= self`). """ - + return _create_node_with_operator(operator.__ge__, other, self) From db0bf870272e1457f5c6bc3a50af17379cc24778 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 17:23:16 +0100 Subject: [PATCH 092/105] Update core.py --- deeptrack/backend/core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index ec82a0eab..20154f0a0 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -1026,7 +1026,7 @@ def __hash__(self) -> int: Uses the node’s `id` to ensure uniqueness. """ - + return id(self) def __getitem__(self, idx: Any) -> 'DeepTrackNode': @@ -1191,7 +1191,7 @@ def __rmul__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': return _create_node_with_operator(operator.__mul__, other, self) def __truediv__( - self, + self, other: Union['DeepTrackNode', Any], ) -> 'DeepTrackNode': """Divide node by another node or value. @@ -1214,7 +1214,7 @@ def __truediv__( return _create_node_with_operator(operator.__truediv__, self, other) def __rtruediv__( - self, + self, other: Union['DeepTrackNode', Any], ) -> 'DeepTrackNode': """Divide other value by node (right-hand). @@ -1237,7 +1237,7 @@ def __rtruediv__( return _create_node_with_operator(operator.__truediv__, other, self) def __floordiv__( - self, + self, other: Union['DeepTrackNode', Any], ) -> 'DeepTrackNode': """Perform floor division of node by another node or value. @@ -1262,7 +1262,7 @@ def __floordiv__( return _create_node_with_operator(operator.__floordiv__, self, other) def __rfloordiv__( - self, + self, other: Union['DeepTrackNode', Any], ) -> 'DeepTrackNode': """Perform floor division of other value by node (right-hand). From 88994b2bf15a9d9bed490e19150b440058360e5d Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 20:18:23 +0100 Subject: [PATCH 093/105] Update core.py --- deeptrack/backend/core.py | 92 ++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 12 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 20154f0a0..4a864ea77 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -99,6 +99,35 @@ class DeepTrackDataObject: validate() Marks the data as valid. + Example + ------- + Create a `DeepTrackDataObject`: + + >>> data_obj = core.DeepTrackDataObject() + + Store a value in this container: + + >>> data_obj.store(42) + >>> print(data_obj.current_value()) + 42 + + Check if the stored data is valid: + + >>> print(data_obj.is_valid()) + True + + Invalidate the stored data: + + >>> data_obj.invalidate() + >>> print(data_obj.is_valid()) + False + + Validate the data again to restore its status: + + >>> data_obj.validate() + >>> print(data_obj.is_valid()) + True + """ # Attributes. @@ -459,28 +488,29 @@ def __contains__(self, _ID: Tuple[int, ...]) -> bool: class DeepTrackNode: """Object corresponding to a node in a computation graph. - This class represents a node within a computation graph, where each node - can store data and compute new values based on its dependencies. The value - of a node is computed by calling its `action` method. + `DeepTrackNode` represents a node within a DeepTrack2 computation graph. + In the DeepTrack2 computation graph, each node can store data and compute + new values based on its dependencies. The value of a node is computed by + calling its `action` method. Attributes ---------- data : DeepTrackDataDict - A dictionary-like object for storing data, indexed by tuples of ints. + Dictionary-like object for storing data, indexed by tuples of integers. children : WeakSet[DeepTrackNode] - Set of nodes that depend on this node. + Nodes that depend on this node (its parents, grandparents, etc.). dependencies : WeakSet[DeepTrackNode] - Set of nodes on which this node depends. + Nodes on which this node depends (its children, grandchildren, etc.). _action : Callable - The function or lambda to compute new values. + The function or lambda-function to compute the node value. _accepts_ID : bool - Whether `action` accepts `_ID`. + Whether `action` accepts an input ID. _all_subchildren : Set[DeepTrackNode] All nodes in the subtree rooted at this node, including itself. citations : List[str] Citations associated with this node. - Methods + Methods ------- action : property Get/set the computation function. @@ -524,6 +554,44 @@ class DeepTrackNode: __getitem__(idx: Any) -> DeepTrackNode Index into the node’s computed data. + Example + ------- + Create two `DeepTrackNode` objects: + + >>> parent = DeepTrackNode(action=lambda: 10) + >>> child = DeepTrackNode(action=lambda _ID=None: parent(_ID) * 2) + + First, establish the dependency between `parent` and `child`: + + >>> parent.add_child(child) + + Store values in the parent node for specific IDs: + + >>> parent.store(15, _ID=(0,)) + >>> parent.store(20, _ID=(1,)) + + Compute the values for the child node based on these parent values: + + >>> child_value_0 = child(_ID=(0,)) + >>> child_value_1 = child(_ID=(1,)) + >>> print(child_value_0, child_value_1) + 30 40 + + Invalidate the parent data for a specific ID: + + >>> parent.invalidate((0,)) + >>> print(parent.is_valid((0,))) + False + >>> print(child.is_valid((0,))) + False + + Update the parent value and recompute the child value: + + >>> parent.store(25, _ID=(0,)) + >>> child_value_recomputed = child(_ID=(0,)) + >>> print(child_value_recomputed) + 50 + """ # Attributes. @@ -566,8 +634,8 @@ def action(self, value: Callable[..., Any]) -> None: self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") def __init__( - self, - action: Optional[Callable[..., Any]] = None, + self, + action: Optional[Callable[..., Any]] = None, **kwargs: Any, ): """Initialize a new DeepTrackNode. @@ -587,7 +655,7 @@ def __init__( self.dependencies = WeakSet() self._action = lambda: None # Default no-op action. - # If action is provided, set it. If it's callable, use it directly; + # If action is provided, set it. If it's callable, use it directly; # otherwise, wrap it in a lambda. if action is not None: if callable(action): From b38eebda3cd21648eee4a8c880f4053fa08f518a Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 20:28:55 +0100 Subject: [PATCH 094/105] Update core.py --- deeptrack/backend/core.py | 56 +++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index 4a864ea77..f808c4828 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -513,46 +513,50 @@ class DeepTrackNode: Methods ------- action : property - Get/set the computation function. + Gets or sets the computation function for the node. add_child(other: DeepTrackNode) -> DeepTrackNode - Adds a child node. + Adds a child node that depends on this node. + Also adds the dependency between the two nodes. add_dependency(other: DeepTrackNode) -> DeepTrackNode - Adds a dependency node. + Adds a dependency, making this node depend on the given node. store(data: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode - Stores computed data. + Stores computed data for the given `_ID`. is_valid(_ID: Tuple[int, ...] = ()) -> bool - Checks if data is valid. + Checks if the data for the given `_ID` is valid. valid_index(_ID: Tuple[int, ...]) -> bool - Checks if `_ID` is valid. + Checks if the given `_ID` is valid for this node. invalidate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode - Invalidates this node’s and its children's data. + Invalidates the data for the given `_ID` and all child nodes. validate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode - Validates this node’s data. - _update() -> DeepTrackNode - Internal method to reset data. + Validates the data for the given `_ID`, marking it as up-to-date, but + not its children. set_value(value: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode - Sets a value, invalidating if necessary. + Sets a value for the given `_ID`. If the new value differs from the + current value, the node is invalidated to ensure dependencies are + recomputed. previous(_ID: Tuple[int, ...] = ()) -> Any - Returns previously stored value. - recurse_children(memory: Optional[Set[DeepTrackNode]] = None) - -> Set[DeepTrackNode] - Returns all subchildren. - old_recurse_children(memory: Optional[List[DeepTrackNode]] = None) - -> Iterator[DeepTrackNode] - Legacy depth-first traversal. - recurse_dependencies(memory: Optional[List[DeepTrackNode]] = None) - -> Iterator[DeepTrackNode] - Yields dependencies. + Returns the previously stored value for the given `_ID` without + recomputing it. + recurse_children( + memory: Optional[Set[DeepTrackNode]] = None + ) -> Set[DeepTrackNode] + Returns all child nodes in the dependency tree rooted at this node. + recurse_dependencies( + memory: Optional[List[DeepTrackNode]] = None + ) -> Iterator[DeepTrackNode] + Yields all nodes that this node depends on, traversing dependencies. get_citations() -> Set[str] - Gathers citations. + Returns a set of citations for this node and its dependencies. __call__(_ID: Tuple[int, ...] = ()) -> Any - Evaluates the node. + Evaluates the node's computation for the given `_ID`, recomputing if + necessary. current_value(_ID: Tuple[int, ...] = ()) -> Any - Returns currently stored value. + Returns the currently stored value for the given `_ID` without + recomputation. __hash__() -> int - Returns unique hash. + Returns a unique hash for this node. __getitem__(idx: Any) -> DeepTrackNode - Index into the node’s computed data. + Creates a new node that indexes into this node’s computed data. Example ------- From 42d7e746a8085293f815bb96b4555021b01b598e Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 21:31:14 +0100 Subject: [PATCH 095/105] Update core.py --- deeptrack/backend/core.py | 112 ++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/deeptrack/backend/core.py b/deeptrack/backend/core.py index f808c4828..276b1dc8d 100644 --- a/deeptrack/backend/core.py +++ b/deeptrack/backend/core.py @@ -514,7 +514,7 @@ class DeepTrackNode: ------- action : property Gets or sets the computation function for the node. - add_child(other: DeepTrackNode) -> DeepTrackNode + add_child(child: DeepTrackNode) -> DeepTrackNode Adds a child node that depends on this node. Also adds the dependency between the two nodes. add_dependency(other: DeepTrackNode) -> DeepTrackNode @@ -530,6 +530,8 @@ class DeepTrackNode: validate(_ID: Tuple[int, ...] = ()) -> DeepTrackNode Validates the data for the given `_ID`, marking it as up-to-date, but not its children. + _update() -> DeepTrackNode + Internal method to reset data. set_value(value: Any, _ID: Tuple[int, ...] = ()) -> DeepTrackNode Sets a value for the given `_ID`. If the new value differs from the current value, the node is invalidated to ensure dependencies are @@ -615,9 +617,9 @@ class DeepTrackNode: def action(self) -> Callable[..., Any]: """Callable: The function that computes this node’s value. - When accessed, returns the current action. This is often a lambda or - function that takes `_ID` as an optional parameter if `_accepts_ID` is - True. + When accessed, returns the current action. This is often a function or + lambda-function that takes `_ID` as an optional parameter if + `_accepts_ID` is True. """ @@ -635,7 +637,7 @@ def action(self, value: Callable[..., Any]) -> None: when calling `action`. """ self._action = value - self._accepts_ID = utils.get_kwarg_names(value).__contains__("_ID") + self._accepts_ID = "_ID" in utils.get_kwarg_names(value) def __init__( self, @@ -647,7 +649,8 @@ def __init__( Parameters ---------- action : Callable or Any, optional - Action to compute this node’s value. If not provided, uses a no-op. + Action to compute this node’s value. If not provided, uses a no-op + action (lambda: None). **kwargs : dict Additional arguments for subclasses or extended functionality. @@ -659,7 +662,8 @@ def __init__( self.dependencies = WeakSet() self._action = lambda: None # Default no-op action. - # If action is provided, set it. If it's callable, use it directly; + # If action is provided, set it. + # If it's callable, use it directly; # otherwise, wrap it in a lambda. if action is not None: if callable(action): @@ -677,34 +681,32 @@ def __init__( self._all_subchildren = set() self._all_subchildren.add(self) - def add_child(self, other: 'DeepTrackNode') -> 'DeepTrackNode': - """Add a child node, indicating that `other` depends on this node. + def add_child(self, child: 'DeepTrackNode') -> 'DeepTrackNode': + """Add a child node to the current node. + + Adding a child also updates `_all_subchildren` for this node and all + its dependencies. It also ensures that dependency and child + relationships remain consistent. Parameters ---------- - other : DeepTrackNode - The node that depends on this node. + child : DeepTrackNode + The child node that depends on this node. Returns ------- self : DeepTrackNode Returns the current node for chaining. - Notes - ----- - Adding a child also updates `_all_subchildren` for this node and all - its dependencies. Ensures that dependency and child relationships - remain consistent. - """ - self.children.add(other) - if self not in other.dependencies: - other.add_dependency(self) # Ensure bidirectional relationship. + self.children.add(child) + if self not in child.dependencies: + child.add_dependency(self) # Ensure bidirectional relationship. - # Get all subchildren of `other` and add `other` itself. - subchildren = other._all_subchildren.copy() - subchildren.add(other) + # Get all subchildren of `child` and add `child` itself. + subchildren = child._all_subchildren.copy() + subchildren.add(child) # Merge all these subchildren into this node’s subtree. self._all_subchildren = self._all_subchildren.union(subchildren) @@ -714,14 +716,14 @@ def add_child(self, other: 'DeepTrackNode') -> 'DeepTrackNode': return self - def add_dependency(self, other: 'DeepTrackNode') -> 'DeepTrackNode': - """Add a dependency node indicating this node depends on `other`. + def add_dependency(self, parent: 'DeepTrackNode') -> 'DeepTrackNode': + """Adds a dependency, making this node depend on a parent node. Parameters ---------- - other : DeepTrackNode - The node that this node depends on. If `other` changes, this node’s - data may become invalid. + parent : DeepTrackNode + The parent node that this node depends on. If `parent` changes, + this node’s data may become invalid. Returns ------- @@ -730,8 +732,9 @@ def add_dependency(self, other: 'DeepTrackNode') -> 'DeepTrackNode': """ - self.dependencies.add(other) - other.add_child(self) # Ensure the child relationship is also set. + self.dependencies.add(parent) + + parent.add_child(self) # Ensure the child relationship is also set. return self @@ -741,14 +744,15 @@ def store(self, data: Any, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': Parameters ---------- data : Any - The data to store. + The data to be store. _ID : Tuple[int, ...], optional - The index for this data. Default is the empty tuple, indicating a - root-level entry. + The index for this data. Default is the empty tuple (), indicating + a root-level entry. Returns ------- self : DeepTrackNode + Returns the current node for chaining. """ @@ -779,7 +783,7 @@ def is_valid(self, _ID: Tuple[int, ...] = ()) -> bool: return False def valid_index(self, _ID: Tuple[int, ...]) -> bool: - """Check if `_ID` is a valid index for this node’s data. + """Check if ID is a valid index for this node’s data. Parameters ---------- @@ -807,11 +811,12 @@ def invalidate(self, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': Returns ------- self : DeepTrackNode + Returns the current node for chaining. Note ---- At the moment, the code to invalidate specific IDs is not implemented, - so the _ID parameter is not used. + so the _ID parameter is not effectively used. """ @@ -850,10 +855,11 @@ def _update(self) -> 'DeepTrackNode': Returns ------- self : DeepTrackNode + Returns the current node for chaining. """ - - # Pre-instantiate memory for optimization used to avoid repeated + + # Pre-instantiate memory for optimization used to avoid repeated # processing of the same nodes. child_memory = [] @@ -865,7 +871,7 @@ def _update(self) -> 'DeepTrackNode': return self def set_value(self, value, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': - """Set a value for this node’s data at `_ID`. + """Set a value for this node’s data at ID. If the value is different from the currently stored one (or if it is invalid), it will invalidate the old data before storing the new one. @@ -880,11 +886,12 @@ def set_value(self, value, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': Returns ------- self : DeepTrackNode + Returns the current node for chaining. """ - # Check if current value is equivalent. If not, invalidate and store - # the new value. If set to same value, no need to invalidate + # Check if current value is equivalent. If not, invalidate and store + # the new value. If set to same value, no need to invalidate. if not ( self.is_valid(_ID=_ID) and _equivalent(value, self.data[_ID].current_value()) @@ -895,7 +902,7 @@ def set_value(self, value, _ID: Tuple[int, ...] = ()) -> 'DeepTrackNode': return self def previous(self, _ID: Tuple[int, ...] = ()) -> Any: - """Retrieve the previously stored value at `_ID` without recomputing. + """Retrieve the previously stored value at ID without recomputing. Parameters ---------- @@ -977,7 +984,7 @@ def old_recurse_children( yield from child.recurse_children(memory=memory) def recurse_dependencies( - self, + self, memory: Optional[List['DeepTrackNode']] = None, ) -> Iterator['DeepTrackNode']: """Yield all dependencies of this node, ensuring each is visited once. @@ -1015,12 +1022,12 @@ def recurse_dependencies( def get_citations(self) -> Set[str]: """Get citations from this node and all its dependencies. - Gathers citations from this node and all nodes that it depends on. + It gathers citations from this node and all nodes that it depends on. Citations are stored as a class attribute `citations`. Returns ------- - set + Set[str] Set of all citations relevant to this node and its dependency tree. """ @@ -1041,7 +1048,7 @@ def get_citations(self) -> Set[str]: return citations def __call__(self, _ID: Tuple[int, ...] = ()) -> Any: - """Evaluate this node at `_ID`. + """Evaluate this node at ID. If the data at `_ID` is valid, it returns the stored value. Otherwise, it calls `action` to compute a new value, stores it, and returns it. @@ -1063,7 +1070,7 @@ def __call__(self, _ID: Tuple[int, ...] = ()) -> Any: return self.current_value(_ID) except KeyError: pass # Data might have been invalidated or removed. - + # Call action with or without `_ID` depending on `_accepts_ID`. if self._accepts_ID: new_value = self.action(_ID=_ID) @@ -1076,7 +1083,7 @@ def __call__(self, _ID: Tuple[int, ...] = ()) -> Any: return self.current_value(_ID) def current_value(self, _ID: Tuple[int, ...] = ()) -> Any: - """Retrieve the currently stored value at `_ID`. + """Retrieve the currently stored value at ID. Parameters ---------- @@ -1124,17 +1131,16 @@ def __getitem__(self, idx: Any) -> 'DeepTrackNode': # Create a new node whose action indexes into this node’s result. node = DeepTrackNode(lambda _ID=None: self(_ID=_ID)[idx]) - node.add_dependency(self) - self.add_child(node) + # node.add_dependency(self) # Already executed by add_child. return node # Node-node operators. - # These methods define arithmetic and comparison operations for - # DeepTrackNode objects. Each operation creates a new DeepTrackNode that - # represents the result of applying the corresponding operator to `self` - # and `other`. The operators are applied lazily and will be computed only + # These methods define arithmetic and comparison operations for + # DeepTrackNode objects. Each operation creates a new DeepTrackNode that + # represents the result of applying the corresponding operator to `self` + # and `other`. The operators are applied lazily and will be computed only # when the resulting node is evaluated. def __add__(self, other: Union['DeepTrackNode', Any]) -> 'DeepTrackNode': From b1acbac3dee648a0b11f770f4fbd12a6ad59c518 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 21:36:11 +0100 Subject: [PATCH 096/105] Update utils.py --- deeptrack/utils.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/deeptrack/utils.py b/deeptrack/utils.py index cfd9d1567..5d5ee6459 100644 --- a/deeptrack/utils.py +++ b/deeptrack/utils.py @@ -6,17 +6,18 @@ Functions --------- hasmethod(obj: any, method_name: str) -> bool - Return True if the object has a field named `function_name` that is - callable. Otherwise, return False. + Returns True if the object has a field named `function_name` that is + callable. Otherwise, returns False. as_list(obj: any) -> list - If the input is iterable, convert it to list. - Otherwise, wrap the input in a list. + If the input is iterable, converts it to list. + Otherwise, wraps the input in a list. get_kwarg_names(function: Callable) -> List[str] Retrieves the names of the keyword arguments accepted by a function. kwarg_has_default(function: Callable, argument: str) -> bool Checks if a specific argument of a function has a default value. safe_call(function, positional_args=[], **kwargs) - Calls a function, passing only valid arguments from the provided kwargs. + Calls a function, passing only valid arguments from the provided keyword + arguments (kwargs). """ @@ -42,7 +43,7 @@ def hasmethod(obj: any, method_name: str) -> bool: """ - return (hasattr(obj, method_name) + return (hasattr(obj, method_name) and callable(getattr(obj, method_name, None))) @@ -73,7 +74,7 @@ def as_list(obj: any) -> list: def get_kwarg_names(function: Callable) -> List[str]: """Retrieve the names of the keyword arguments accepted by a function. - Retrieves the names of the keyword arguments accepted by `function` as a + It retrieves the names of the keyword arguments accepted by `function` as a list of strings. Parameters @@ -129,8 +130,8 @@ def kwarg_has_default(function: Callable, argument: str) -> bool: def safe_call(function, positional_args=[], **kwargs) -> Any: """Calls a function with valid arguments from a dictionary of arguments. - Filters `kwargs` to include only arguments accepted by the function, - ensuring that no invalid arguments are passed. This function also supports + It filters `kwargs` to include only arguments accepted by the function, + ensuring that no invalid arguments are passed. This function also supports positional arguments. Parameters @@ -157,4 +158,4 @@ def safe_call(function, positional_args=[], **kwargs) -> Any: if key in kwargs: input_arguments[key] = kwargs[key] - return function(*positional_args, **input_arguments) \ No newline at end of file + return function(*positional_args, **input_arguments) From b7cad7b333ed68a60fd1adb0b26ead721f07b208 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 21:36:56 +0100 Subject: [PATCH 097/105] Update .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8680bb6b3..b1b33a061 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ examples/**/*/models/ *.jpg *.jpeg *.npy -*.db \ No newline at end of file +*.db + +.DS_Store \ No newline at end of file From 820aa78f1ac170cbd4b281ba3c81176e0b7c66e1 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 21:38:46 +0100 Subject: [PATCH 098/105] Update test_utils.py --- deeptrack/test/test_utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index 61bb3f0cc..8481e685b 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -1,3 +1,7 @@ +# pylint: disable=C0115:missing-class-docstring +# pylint: disable=C0116:missing-function-docstring +# pylint: disable=C0103:invalid-name + # Use this only when running the test locally. # import sys # sys.path.append(".") # Adds the module to path. @@ -8,13 +12,13 @@ class TestUtils(unittest.TestCase): - + def test_hasmethod(self): self.assertTrue(utils.hasmethod(utils, "hasmethod")) self.assertFalse( utils.hasmethod(utils, "this_is_definetely_not_a_method_of_utils") ) - + def test_as_list(self): obj = 1 @@ -102,4 +106,4 @@ def func6(key1, key2=1, key3=3, **kwargs): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From a8556fc6572e7b3e53858895fb315f552613560b Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 22:08:28 +0100 Subject: [PATCH 099/105] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b1b33a061..531776fe8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +trial*.ipynb + **/.ipynb_checkpoints **/__pycache__ deeptrack-app/* From 831bcad082c11b08ae012ed268a8beda9abe0a56 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Sun, 8 Dec 2024 22:11:41 +0100 Subject: [PATCH 100/105] Update types.py --- deeptrack/types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deeptrack/types.py b/deeptrack/types.py index 389f410d0..ae1815429 100644 --- a/deeptrack/types.py +++ b/deeptrack/types.py @@ -5,11 +5,13 @@ maintainability, and reduces redundancy in type annotations. These types are particularly useful for properties and array-like structures used within the library. + """ -import numpy as np import typing +import numpy as np + # T is a generic type variable defining generic types for reusability. T = typing.TypeVar("T") From 77754f8acf4b5fed44e8138a807255e2caa45dc8 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Mon, 9 Dec 2024 00:29:31 +0100 Subject: [PATCH 101/105] Delete pint_definition.py --- deeptrack/backend/pint_definition.py | 994 --------------------------- 1 file changed, 994 deletions(-) delete mode 100644 deeptrack/backend/pint_definition.py diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py deleted file mode 100644 index 1c75457b0..000000000 --- a/deeptrack/backend/pint_definition.py +++ /dev/null @@ -1,994 +0,0 @@ -"""Pint constants and units definition for DeepTrack2. - -This file consolidates and extends the default definitions provided by Pint's -`default_en.txt` and `constants_en.txt` files. These files define physical -constants and unit systems based on internationally recognized standards, such -as the International System of Units (SI), and additional systems like CGS, -Planck units, and atomic units. - -Sources: --------- -- Pint's default unit definitions: - https://github.com/hgrecco/pint/blob/main/pint/default_en.txt -- Pint's default constants definitions: - https://github.com/hgrecco/pint/blob/main/pint/constants_en.txt - -Content: --------- -- Mathematical Constants: Includes key values like π, Euler's number, - and the natural logarithm of 10. -- Physical Constants: Covers fundamental constants like the speed of light, - Planck constant, and Boltzmann constant. -- Derived Constants: Defines values such as the fine-structure constant and - classical electron radius. -- Units: Provides base and derived units for length, mass, time, energy, etc., - with precise conversion factors. -- Prefixes and Aliases: Defines standard prefixes (e.g., milli-, kilo-, mega-) - and unit aliases to ensure flexibility. -- Unit Systems: Details unit systems, including SI, MKS, CGS, Planck, and - imperial units. -- Contexts and Conversion: Includes context-specific definitions to facilitate - domain-specific conversions. - -Key Modifications: ------------------- -This file is derived from the default Pint files with the adjustments: -1. Groups Removed: Unit group definitions (e.g., `@group`) have been excluded - to avoid conflicts with the definition of pixel. -2. Final Variables Added: Defines constants and variables required for the - project-specific context (e.g., pixel-related units). - -Usage: ------- -To create a unit registry with custom pixel-related units: - ->>> from pint import UnitRegistry ->>> from .backend.pint_definition import pint_definitions ->>> ->>> units = UnitRegistry(pint_definitions.split("\n")) - -""" - - -pint_constants = """ -# Default Pint constants definition file -# Based on the International System of Units -# Language: english -# Source: https://physics.nist.gov/cuu/Constants/ -# https://physics.nist.gov/PhysRefData/XrayTrans/Html/search.html -# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. - -#### MATHEMATICAL CONSTANTS #### -# As computed by Maxima with fpprec:50 - -pi = 3.1415926535897932384626433832795028841971693993751 = π # pi -tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian -ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 -wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 -wien_u = 2.8214393721220788934031913302944851953458817440731 # solution to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3 -eulers_number = 2.71828182845904523536028747135266249775724709369995 - -#### DEFINED EXACT CONSTANTS #### - -speed_of_light = 299792458 m/s = c = c_0 # since 1983 -planck_constant = 6.62607015e-34 J s = h # since May 2019 -elementary_charge = 1.602176634e-19 C = e # since May 2019 -avogadro_number = 6.02214076e23 # since May 2019 -boltzmann_constant = 1.380649e-23 J K^-1 = k = k_B # since May 2019 -standard_gravity = 9.80665 m/s^2 = g_0 = g0 = g_n = gravity # since 1901 -standard_atmosphere = 1.01325e5 Pa = atm = atmosphere # since 1954 -conventional_josephson_constant = 4.835979e14 Hz / V = K_J90 # since Jan 1990 -conventional_von_klitzing_constant = 2.5812807e4 ohm = R_K90 # since Jan 1990 - -#### DERIVED EXACT CONSTANTS #### -# Floating-point conversion may introduce inaccuracies - -zeta = c / (cm/s) = ζ -dirac_constant = h / (2 * π) = ħ = hbar = atomic_unit_of_action = a_u_action -avogadro_constant = avogadro_number * mol^-1 = N_A -molar_gas_constant = k * N_A = R -faraday_constant = e * N_A -conductance_quantum = 2 * e ** 2 / h = G_0 -magnetic_flux_quantum = h / (2 * e) = Φ_0 = Phi_0 -josephson_constant = 2 * e / h = K_J -von_klitzing_constant = h / e ** 2 = R_K -stefan_boltzmann_constant = 2 / 15 * π ** 5 * k ** 4 / (h ** 3 * c ** 2) = σ = sigma -first_radiation_constant = 2 * π * h * c ** 2 = c_1 -second_radiation_constant = h * c / k = c_2 -wien_wavelength_displacement_law_constant = h * c / (k * wien_x) -wien_frequency_displacement_law_constant = wien_u * k / h - -#### MEASURED CONSTANTS #### -# Recommended CODATA-2018 values -# To some extent, what is measured and what is derived is a bit arbitrary. -# The choice of measured constants is based on convenience and on available uncertainty. -# The uncertainty in the last significant digits is given in parentheses as a comment. - -newtonian_constant_of_gravitation = 6.67430e-11 m^3/(kg s^2) = _ = gravitational_constant # (15) -rydberg_constant = 1.0973731568160e7 * m^-1 = R_∞ = R_inf # (21) -electron_g_factor = -2.00231930436256 = g_e # (35) -atomic_mass_constant = 1.66053906660e-27 kg = m_u # (50) -electron_mass = 9.1093837015e-31 kg = m_e = atomic_unit_of_mass = a_u_mass # (28) -proton_mass = 1.67262192369e-27 kg = m_p # (51) -neutron_mass = 1.67492749804e-27 kg = m_n # (95) -lattice_spacing_of_Si = 1.920155716e-10 m = d_220 # (32) -K_alpha_Cu_d_220 = 0.80232719 # (22) -K_alpha_Mo_d_220 = 0.36940604 # (19) -K_alpha_W_d_220 = 0.108852175 # (98) - -#### DERIVED CONSTANTS #### - -fine_structure_constant = (2 * h * R_inf / (m_e * c)) ** 0.5 = α = alpha -vacuum_permeability = 2 * α * h / (e ** 2 * c) = µ_0 = mu_0 = mu0 = magnetic_constant -vacuum_permittivity = e ** 2 / (2 * α * h * c) = ε_0 = epsilon_0 = eps_0 = eps0 = electric_constant -impedance_of_free_space = 2 * α * h / e ** 2 = Z_0 = characteristic_impedance_of_vacuum -coulomb_constant = α * hbar * c / e ** 2 = k_C -classical_electron_radius = α * hbar / (m_e * c) = r_e -thomson_cross_section = 8 / 3 * π * r_e ** 2 = σ_e = sigma_e -""" - -pint_definitions = f""" -# Default Pint units definition file -# Based on the International System of Units -# Language: english -# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. - -# Syntax -# ====== -# Units -# ----- -# = [= ] [= ] [ = ] [...] -# -# The canonical name and aliases should be expressed in singular form. -# Pint automatically deals with plurals built by adding 's' to the singular form; plural -# forms that don't follow this rule should be instead explicitly listed as aliases. -# -# If a unit has no symbol and one wants to define aliases, then the symbol should be -# conventionally set to _. -# -# Example: -# millennium = 1e3 * year = _ = millennia -# -# -# Prefixes -# -------- -# - = [= ] [= ] [ = ] [...] -# -# Example: -# deca- = 1e+1 = da- = deka- -# -# -# Derived dimensions -# ------------------ -# [dimension name] = -# -# Example: -# [density] = [mass] / [volume] -# -# Note that primary dimensions don't need to be declared; they can be -# defined for the first time in a unit definition. -# E.g. see below `meter = [length]` -# -# -# Additional aliases -# ------------------ -# @alias = [ = ] [...] -# -# Used to add aliases to already existing unit definitions. -# Particularly useful when one wants to enrich definitions -# from defaults_en.txt with custom aliases. -# -# Example: -# @alias meter = my_meter - -# See also: https://pint.readthedocs.io/en/latest/defining.html - -@defaults - group = international - system = mks -@end - - -#### PREFIXES #### - -# decimal prefixes -yocto- = 1e-24 = y- -zepto- = 1e-21 = z- -atto- = 1e-18 = a- -femto- = 1e-15 = f- -pico- = 1e-12 = p- -nano- = 1e-9 = n- -micro- = 1e-6 = µ- = u- -milli- = 1e-3 = m- -centi- = 1e-2 = c- -deci- = 1e-1 = d- -deca- = 1e+1 = da- = deka- -hecto- = 1e2 = h- -kilo- = 1e3 = k- -mega- = 1e6 = M- -giga- = 1e9 = G- -tera- = 1e12 = T- -peta- = 1e15 = P- -exa- = 1e18 = E- -zetta- = 1e21 = Z- -yotta- = 1e24 = Y- - -# binary_prefixes -kibi- = 2**10 = Ki- -mebi- = 2**20 = Mi- -gibi- = 2**30 = Gi- -tebi- = 2**40 = Ti- -pebi- = 2**50 = Pi- -exbi- = 2**60 = Ei- -zebi- = 2**70 = Zi- -yobi- = 2**80 = Yi- - -# extra_prefixes -semi- = 0.5 = _ = demi- -sesqui- = 1.5 - - -#### BASE UNITS #### - -meter = [length] = m = metre -second = [time] = s = sec -ampere = [current] = A = amp -candela = [luminosity] = cd = candle -gram = [mass] = g -mole = [substance] = mol -kelvin = [temperature]; offset: 0 = K = degK = °K = degree_Kelvin = degreeK # older names supported for compatibility -radian = [] = rad -bit = [] -count = [] - - -#### CONSTANTS #### - -{pint_constants} - - -#### UNITS #### -# Common and less common, grouped by quantity. -# Conversion factors are exact (except when noted), -# although floating-point conversion may introduce inaccuracies - -# Angle -turn = 2 * π * radian = _ = revolution = cycle = circle -degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree -arcminute = degree / 60 = arcmin = arc_minute = angular_minute -arcsecond = arcminute / 60 = arcsec = arc_second = angular_second -milliarcsecond = 1e-3 * arcsecond = mas -grade = π / 200 * radian = grad = gon -mil = π / 32000 * radian - -# Solid angle -steradian = radian ** 2 = sr -square_degree = (π / 180) ** 2 * sr = sq_deg = sqdeg - -# Information -baud = bit / second = Bd = bps - -byte = 8 * bit = B = octet -# byte = 8 * bit = _ = octet -## NOTE: B (byte) symbol can conflict with Bell - -# Length -angstrom = 1e-10 * meter = Å = ångström = Å -micron = micrometer = µ -fermi = femtometer = fm -light_year = speed_of_light * julian_year = ly = lightyear -astronomical_unit = 149597870700 * meter = au # since Aug 2012 -parsec = 1 / tansec * astronomical_unit = pc -nautical_mile = 1852 * meter = nmi -bohr = hbar / (alpha * m_e * c) = a_0 = a0 = bohr_radius = atomic_unit_of_length = a_u_length -x_unit_Cu = K_alpha_Cu_d_220 * d_220 / 1537.4 = Xu_Cu -x_unit_Mo = K_alpha_Mo_d_220 * d_220 / 707.831 = Xu_Mo -angstrom_star = K_alpha_W_d_220 * d_220 / 0.2090100 = Å_star -planck_length = (hbar * gravitational_constant / c ** 3) ** 0.5 - -# Mass -metric_ton = 1e3 * kilogram = t = tonne -unified_atomic_mass_unit = atomic_mass_constant = u = amu -dalton = atomic_mass_constant = Da -grain = 64.79891 * milligram = gr -gamma_mass = microgram -carat = 200 * milligram = ct = karat -planck_mass = (hbar * c / gravitational_constant) ** 0.5 - -# Time -minute = 60 * second = min -hour = 60 * minute = hr -day = 24 * hour = d -week = 7 * day -fortnight = 2 * week -year = 365.25 * day = a = yr = julian_year -month = year / 12 - -# decade = 10 * year -## NOTE: decade [time] can conflict with decade [dimensionless] - -century = 100 * year = _ = centuries -millennium = 1e3 * year = _ = millennia -eon = 1e9 * year -shake = 1e-8 * second -svedberg = 1e-13 * second -atomic_unit_of_time = hbar / E_h = a_u_time -gregorian_year = 365.2425 * day -sidereal_year = 365.256363004 * day # approximate, as of J2000 epoch -tropical_year = 365.242190402 * day # approximate, as of J2000 epoch -common_year = 365 * day -leap_year = 366 * day -sidereal_day = day / 1.00273790935079524 # approximate -sidereal_month = 27.32166155 * day # approximate -tropical_month = 27.321582 * day # approximate -synodic_month = 29.530589 * day = _ = lunar_month # approximate -planck_time = (hbar * gravitational_constant / c ** 5) ** 0.5 - -# Temperature -degree_Celsius = kelvin; offset: 273.15 = °C = celsius = degC = degreeC -degree_Rankine = 5 / 9 * kelvin; offset: 0 = °R = rankine = degR = degreeR -degree_Fahrenheit = 5 / 9 * kelvin; offset: 233.15 + 200 / 9 = °F = fahrenheit = degF = degreeF -degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degreeRe = degree_Réaumur = réaumur -atomic_unit_of_temperature = E_h / k = a_u_temp -planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5 - -# Area -[area] = [length] ** 2 -are = 100 * meter ** 2 -barn = 1e-28 * meter ** 2 = b -darcy = centipoise * centimeter ** 2 / (second * atmosphere) -hectare = 100 * are = ha - -# Volume -[volume] = [length] ** 3 -liter = decimeter ** 3 = l = L = litre -cubic_centimeter = centimeter ** 3 = cc -lambda = microliter = λ -stere = meter ** 3 - -# Frequency -[frequency] = 1 / [time] -hertz = 1 / second = Hz -revolutions_per_minute = revolution / minute = rpm -revolutions_per_second = revolution / second = rps -counts_per_second = count / second = cps - -# Wavenumber -[wavenumber] = 1 / [length] -reciprocal_centimeter = 1 / cm = cm_1 = kayser - -# Velocity -[velocity] = [length] / [time] -[speed] = [velocity] -knot = nautical_mile / hour = kt = knot_international = international_knot -mile_per_hour = mile / hour = mph = MPH -kilometer_per_hour = kilometer / hour = kph = KPH -kilometer_per_second = kilometer / second = kps -meter_per_second = meter / second = mps -foot_per_second = foot / second = fps - -# Acceleration -[acceleration] = [velocity] / [time] -galileo = centimeter / second ** 2 = Gal - -# Force -[force] = [mass] * [acceleration] -newton = kilogram * meter / second ** 2 = N -dyne = gram * centimeter / second ** 2 = dyn -force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond -force_gram = g_0 * gram = gf = gram_force -force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force -atomic_unit_of_force = E_h / a_0 = a_u_force - -# Energy -[energy] = [force] * [length] -joule = newton * meter = J -erg = dyne * centimeter -watt_hour = watt * hour = Wh = watthour -electron_volt = e * volt = eV -rydberg = h * c * R_inf = Ry -hartree = 2 * rydberg = E_h = Eh = hartree_energy = atomic_unit_of_energy = a_u_energy -calorie = 4.184 * joule = cal = thermochemical_calorie = cal_th -international_calorie = 4.1868 * joule = cal_it = international_steam_table_calorie -fifteen_degree_calorie = 4.1855 * joule = cal_15 -british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso -international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it -thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th -quadrillion_Btu = 1e15 * Btu = quad -therm = 1e5 * Btu = thm = EC_therm -US_therm = 1.054804e8 * joule # approximate, no exact definition -ton_TNT = 1e9 * calorie = tTNT -tonne_of_oil_equivalent = 1e10 * international_calorie = toe -atmosphere_liter = atmosphere * liter = atm_l - -# Power -[power] = [energy] / [time] -watt = joule / second = W -volt_ampere = volt * ampere = VA -horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower -boiler_horsepower = 33475 * Btu / hour # unclear which Btu -metric_horsepower = 75 * force_kilogram * meter / second -electrical_horsepower = 746 * watt -refrigeration_ton = 12e3 * Btu / hour = _ = ton_of_refrigeration # approximate, no exact definition -standard_liter_per_minute = atmosphere * liter / minute = slpm = slm -conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90 - -# Momentum -[momentum] = [length] * [mass] / [time] - -# Density (as auxiliary for pressure) -[density] = [mass] / [volume] -mercury = 13.5951 * kilogram / liter = Hg = Hg_0C = Hg_32F = conventional_mercury -water = 1.0 * kilogram / liter = H2O = conventional_water -mercury_60F = 13.5568 * kilogram / liter = Hg_60F # approximate -water_39F = 0.999972 * kilogram / liter = water_4C # approximate -water_60F = 0.999001 * kilogram / liter # approximate - -# Pressure -[pressure] = [force] / [area] -pascal = newton / meter ** 2 = Pa -barye = dyne / centimeter ** 2 = Ba = barie = barad = barrie = baryd -bar = 1e5 * pascal -technical_atmosphere = kilogram * g_0 / centimeter ** 2 = at -torr = atm / 760 -pound_force_per_square_inch = force_pound / inch ** 2 = psi -kip_per_square_inch = kip / inch ** 2 = ksi -millimeter_Hg = millimeter * Hg * g_0 = mmHg = mm_Hg = millimeter_Hg_0C -centimeter_Hg = centimeter * Hg * g_0 = cmHg = cm_Hg = centimeter_Hg_0C -inch_Hg = inch * Hg * g_0 = inHg = in_Hg = inch_Hg_32F -inch_Hg_60F = inch * Hg_60F * g_0 -inch_H2O_39F = inch * water_39F * g_0 -inch_H2O_60F = inch * water_60F * g_0 -foot_H2O = foot * water * g_0 = ftH2O = feet_H2O -centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O -sound_pressure_level = 20e-6 * pascal = SPL - -# Torque -[torque] = [force] * [length] -foot_pound = foot * force_pound = ft_lb = footpound - -# Viscosity -[viscosity] = [pressure] * [time] -poise = 0.1 * Pa * second = P -reyn = psi * second - -# Kinematic viscosity -[kinematic_viscosity] = [area] / [time] -stokes = centimeter ** 2 / second = St - -# Fluidity -[fluidity] = 1 / [viscosity] -rhe = 1 / poise - -# Amount of substance -particle = 1 / N_A = _ = molec = molecule - -# Concentration -[concentration] = [substance] / [volume] -molar = mole / liter = M - -# Catalytic activity -[activity] = [substance] / [time] -katal = mole / second = kat -enzyme_unit = micromole / minute = U = enzymeunit - -# Entropy -[entropy] = [energy] / [temperature] -clausius = calorie / kelvin = Cl - -# Molar entropy -[molar_entropy] = [entropy] / [substance] -entropy_unit = calorie / kelvin / mole = eu - -# Radiation -becquerel = counts_per_second = Bq -curie = 3.7e10 * becquerel = Ci -rutherford = 1e6 * becquerel = Rd -gray = joule / kilogram = Gy -sievert = joule / kilogram = Sv -rads = 0.01 * gray -rem = 0.01 * sievert -roentgen = 2.58e-4 * coulomb / kilogram = _ = röntgen # approximate, depends on medium - -# Heat transimission -[heat_transmission] = [energy] / [area] -peak_sun_hour = 1e3 * watt_hour / meter ** 2 = PSH -langley = thermochemical_calorie / centimeter ** 2 = Ly - -# Luminance -[luminance] = [luminosity] / [area] -nit = candela / meter ** 2 -stilb = candela / centimeter ** 2 -lambert = 1 / π * candela / centimeter ** 2 - -# Luminous flux -[luminous_flux] = [luminosity] -lumen = candela * steradian = lm - -# Illuminance -[illuminance] = [luminous_flux] / [area] -lux = lumen / meter ** 2 = lx - -# Intensity -[intensity] = [power] / [area] -atomic_unit_of_intensity = 0.5 * ε_0 * c * atomic_unit_of_electric_field ** 2 = a_u_intensity - -# Current -biot = 10 * ampere = Bi -abampere = biot = abA -atomic_unit_of_current = e / atomic_unit_of_time = a_u_current -mean_international_ampere = mean_international_volt / mean_international_ohm = A_it -US_international_ampere = US_international_volt / US_international_ohm = A_US -conventional_ampere_90 = K_J90 * R_K90 / (K_J * R_K) * ampere = A_90 -planck_current = (c ** 6 / gravitational_constant / k_C) ** 0.5 - -# Charge -[charge] = [current] * [time] -coulomb = ampere * second = C -abcoulomb = 10 * C = abC -faraday = e * N_A * mole -conventional_coulomb_90 = K_J90 * R_K90 / (K_J * R_K) * coulomb = C_90 -ampere_hour = ampere * hour = Ah - -# Electric potential -[electric_potential] = [energy] / [charge] -volt = joule / coulomb = V -abvolt = 1e-8 * volt = abV -mean_international_volt = 1.00034 * volt = V_it # approximate -US_international_volt = 1.00033 * volt = V_US # approximate -conventional_volt_90 = K_J90 / K_J * volt = V_90 - -# Electric field -[electric_field] = [electric_potential] / [length] -atomic_unit_of_electric_field = e * k_C / a_0 ** 2 = a_u_electric_field - -# Electric displacement field -[electric_displacement_field] = [charge] / [area] - -# Resistance -[resistance] = [electric_potential] / [current] -ohm = volt / ampere = Ω -abohm = 1e-9 * ohm = abΩ -mean_international_ohm = 1.00049 * ohm = Ω_it = ohm_it # approximate -US_international_ohm = 1.000495 * ohm = Ω_US = ohm_US # approximate -conventional_ohm_90 = R_K / R_K90 * ohm = Ω_90 = ohm_90 - -# Resistivity -[resistivity] = [resistance] * [length] - -# Conductance -[conductance] = [current] / [electric_potential] -siemens = ampere / volt = S = mho -absiemens = 1e9 * siemens = abS = abmho - -# Capacitance -[capacitance] = [charge] / [electric_potential] -farad = coulomb / volt = F -abfarad = 1e9 * farad = abF -conventional_farad_90 = R_K90 / R_K * farad = F_90 - -# Inductance -[inductance] = [magnetic_flux] / [current] -henry = weber / ampere = H -abhenry = 1e-9 * henry = abH -conventional_henry_90 = R_K / R_K90 * henry = H_90 - -# Magnetic flux -[magnetic_flux] = [electric_potential] * [time] -weber = volt * second = Wb -unit_pole = µ_0 * biot * centimeter - -# Magnetic field -[magnetic_field] = [magnetic_flux] / [area] -tesla = weber / meter ** 2 = T -gamma = 1e-9 * tesla = γ - -# Magnetomotive force -[magnetomotive_force] = [current] -ampere_turn = ampere = At -biot_turn = biot -gilbert = 1 / (4 * π) * biot_turn = Gb - -# Magnetic field strength -[magnetic_field_strength] = [current] / [length] - -# Electric dipole moment -[electric_dipole] = [charge] * [length] -debye = 1e-9 / ζ * coulomb * angstrom = D # formally 1 D = 1e-10 Fr*Å, but we generally want to use it outside the Gaussian context - -# Electric quadrupole moment -[electric_quadrupole] = [charge] * [area] -buckingham = debye * angstrom - -# Magnetic dipole moment -[magnetic_dipole] = [current] * [area] -bohr_magneton = e * hbar / (2 * m_e) = µ_B = mu_B -nuclear_magneton = e * hbar / (2 * m_p) = µ_N = mu_N - -# Logaritmic Unit Definition -# Unit = scale; logbase; logfactor -# x_dB = [logfactor] * log( x_lin / [scale] ) / log( [logbase] ) - -# Logaritmic Units of dimensionless quantity: [ https://en.wikipedia.org/wiki/Level_(logarithmic_quantity) ] - -decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm -decibelmicrowatt = 1e-6 watt; logbase: 10; logfactor: 10 = dBu - -decibel = 1 ; logbase: 10; logfactor: 10 = dB -# bell = 1 ; logbase: 10; logfactor: = B -## NOTE: B (Bell) symbol conflicts with byte - -decade = 1 ; logbase: 10; logfactor: 1 -## NOTE: decade [time] can conflict with decade [dimensionless] - -octave = 1 ; logbase: 2; logfactor: 1 = oct - -neper = 1 ; logbase: 2.71828182845904523536028747135266249775724709369995; logfactor: 0.5 = Np -# neper = 1 ; logbase: eulers_number; logfactor: 0.5 = Np - -#### UNIT GROUPS #### -# Mostly for length, area, volume, mass, force -# (customary or specialized units) - -@group USCSLengthInternational - thou = 1e-3 * inch = th = mil_length - inch = yard / 36 = in = international_inch = inches = international_inches - hand = 4 * inch - foot = yard / 3 = ft = international_foot = feet = international_feet - yard = 0.9144 * meter = yd = international_yard # since Jul 1959 - mile = 1760 * yard = mi = international_mile - - circular_mil = π / 4 * mil_length ** 2 = cmil - square_inch = inch ** 2 = sq_in = square_inches - square_foot = foot ** 2 = sq_ft = square_feet - square_yard = yard ** 2 = sq_yd - square_mile = mile ** 2 = sq_mi - - cubic_inch = in ** 3 = cu_in - cubic_foot = ft ** 3 = cu_ft = cubic_feet - cubic_yard = yd ** 3 = cu_yd -@end - -@group USCSLengthSurvey - link = 1e-2 * chain = li = survey_link - survey_foot = 1200 / 3937 * meter = sft - fathom = 6 * survey_foot - rod = 16.5 * survey_foot = rd = pole = perch - chain = 4 * rod - furlong = 40 * rod = fur - cables_length = 120 * fathom - survey_mile = 5280 * survey_foot = smi = us_statute_mile - league = 3 * survey_mile - - square_rod = rod ** 2 = sq_rod = sq_pole = sq_perch - acre = 10 * chain ** 2 - square_survey_mile = survey_mile ** 2 = _ = section - square_league = league ** 2 - - acre_foot = acre * survey_foot = _ = acre_feet -@end - -@group USCSDryVolume - dry_pint = bushel / 64 = dpi = US_dry_pint - dry_quart = bushel / 32 = dqt = US_dry_quart - dry_gallon = bushel / 8 = dgal = US_dry_gallon - peck = bushel / 4 = pk - bushel = 2150.42 cubic_inch = bu - dry_barrel = 7056 cubic_inch = _ = US_dry_barrel - board_foot = ft * ft * in = FBM = board_feet = BF = BDFT = super_foot = superficial_foot = super_feet = superficial_feet -@end - -@group USCSLiquidVolume - minim = pint / 7680 - fluid_dram = pint / 128 = fldr = fluidram = US_fluid_dram = US_liquid_dram - fluid_ounce = pint / 16 = floz = US_fluid_ounce = US_liquid_ounce - gill = pint / 4 = gi = liquid_gill = US_liquid_gill - pint = quart / 2 = pt = liquid_pint = US_pint - fifth = gallon / 5 = _ = US_liquid_fifth - quart = gallon / 4 = qt = liquid_quart = US_liquid_quart - gallon = 231 * cubic_inch = gal = liquid_gallon = US_liquid_gallon -@end - -@group USCSVolumeOther - teaspoon = fluid_ounce / 6 = tsp - tablespoon = fluid_ounce / 2 = tbsp - shot = 3 * tablespoon = jig = US_shot - cup = pint / 2 = cp = liquid_cup = US_liquid_cup - barrel = 31.5 * gallon = bbl - oil_barrel = 42 * gallon = oil_bbl - beer_barrel = 31 * gallon = beer_bbl - hogshead = 63 * gallon -@end - -@group Avoirdupois - dram = pound / 256 = dr = avoirdupois_dram = avdp_dram = drachm - ounce = pound / 16 = oz = avoirdupois_ounce = avdp_ounce - pound = 7e3 * grain = lb = avoirdupois_pound = avdp_pound - stone = 14 * pound - quarter = 28 * stone - bag = 94 * pound - hundredweight = 100 * pound = cwt = short_hundredweight - long_hundredweight = 112 * pound - ton = 2e3 * pound = _ = short_ton - long_ton = 2240 * pound - slug = g_0 * pound * second ** 2 / foot - slinch = g_0 * pound * second ** 2 / inch = blob = slugette - - force_ounce = g_0 * ounce = ozf = ounce_force - force_pound = g_0 * pound = lbf = pound_force - force_ton = g_0 * ton = _ = ton_force = force_short_ton = short_ton_force - force_long_ton = g_0 * long_ton = _ = long_ton_force - kip = 1e3 * force_pound - poundal = pound * foot / second ** 2 = pdl -@end - -@group AvoirdupoisUK using Avoirdupois - UK_hundredweight = long_hundredweight = UK_cwt - UK_ton = long_ton - UK_force_ton = force_long_ton = _ = UK_ton_force -@end - -@group AvoirdupoisUS using Avoirdupois - US_hundredweight = hundredweight = US_cwt - US_ton = ton - US_force_ton = force_ton = _ = US_ton_force -@end - -@group Troy - pennyweight = 24 * grain = dwt - troy_ounce = 480 * grain = toz = ozt - troy_pound = 12 * troy_ounce = tlb = lbt -@end - -@group Apothecary - scruple = 20 * grain - apothecary_dram = 3 * scruple = ap_dr - apothecary_ounce = 8 * apothecary_dram = ap_oz - apothecary_pound = 12 * apothecary_ounce = ap_lb -@end - -@group ImperialVolume - imperial_minim = imperial_fluid_ounce / 480 - imperial_fluid_scruple = imperial_fluid_ounce / 24 - imperial_fluid_drachm = imperial_fluid_ounce / 8 = imperial_fldr = imperial_fluid_dram - imperial_fluid_ounce = imperial_pint / 20 = imperial_floz = UK_fluid_ounce - imperial_gill = imperial_pint / 4 = imperial_gi = UK_gill - imperial_cup = imperial_pint / 2 = imperial_cp = UK_cup - imperial_pint = imperial_gallon / 8 = imperial_pt = UK_pint - imperial_quart = imperial_gallon / 4 = imperial_qt = UK_quart - imperial_gallon = 4.54609 * liter = imperial_gal = UK_gallon - imperial_peck = 2 * imperial_gallon = imperial_pk = UK_pk - imperial_bushel = 8 * imperial_gallon = imperial_bu = UK_bushel - imperial_barrel = 36 * imperial_gallon = imperial_bbl = UK_bbl -@end - -@group Textile - tex = gram / kilometer = Tt - dtex = decitex - denier = gram / (9 * kilometer) = den = Td - jute = pound / (14400 * yard) = Tj - aberdeen = jute = Ta - RKM = gf / tex - - number_english = 840 * yard / pound = Ne = NeC = ECC - number_meter = kilometer / kilogram = Nm -@end - - -#### CGS ELECTROMAGNETIC UNITS #### - -# === Gaussian system of units === -@group Gaussian - franklin = erg ** 0.5 * centimeter ** 0.5 = Fr = statcoulomb = statC = esu - statvolt = erg / franklin = statV - statampere = franklin / second = statA - gauss = dyne / franklin = G - maxwell = gauss * centimeter ** 2 = Mx - oersted = dyne / maxwell = Oe = ørsted - statohm = statvolt / statampere = statΩ - statfarad = franklin / statvolt = statF - statmho = statampere / statvolt -@end -# Note this system is not commensurate with SI, as ε_0 and µ_0 disappear; -# some quantities with different dimensions in SI have the same -# dimensions in the Gaussian system (e.g. [Mx] = [Fr], but [Wb] != [C]), -# and therefore the conversion factors depend on the context (not in pint sense) -[gaussian_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] -[gaussian_current] = [gaussian_charge] / [time] -[gaussian_electric_potential] = [gaussian_charge] / [length] -[gaussian_electric_field] = [gaussian_electric_potential] / [length] -[gaussian_electric_displacement_field] = [gaussian_charge] / [area] -[gaussian_electric_flux] = [gaussian_charge] -[gaussian_electric_dipole] = [gaussian_charge] * [length] -[gaussian_electric_quadrupole] = [gaussian_charge] * [area] -[gaussian_magnetic_field] = [force] / [gaussian_charge] -[gaussian_magnetic_field_strength] = [gaussian_magnetic_field] -[gaussian_magnetic_flux] = [gaussian_magnetic_field] * [area] -[gaussian_magnetic_dipole] = [energy] / [gaussian_magnetic_field] -[gaussian_resistance] = [gaussian_electric_potential] / [gaussian_current] -[gaussian_resistivity] = [gaussian_resistance] * [length] -[gaussian_capacitance] = [gaussian_charge] / [gaussian_electric_potential] -[gaussian_inductance] = [gaussian_electric_potential] * [time] / [gaussian_current] -[gaussian_conductance] = [gaussian_current] / [gaussian_electric_potential] -@context Gaussian = Gau - [gaussian_charge] -> [charge]: value / k_C ** 0.5 - [charge] -> [gaussian_charge]: value * k_C ** 0.5 - [gaussian_current] -> [current]: value / k_C ** 0.5 - [current] -> [gaussian_current]: value * k_C ** 0.5 - [gaussian_electric_potential] -> [electric_potential]: value * k_C ** 0.5 - [electric_potential] -> [gaussian_electric_potential]: value / k_C ** 0.5 - [gaussian_electric_field] -> [electric_field]: value * k_C ** 0.5 - [electric_field] -> [gaussian_electric_field]: value / k_C ** 0.5 - [gaussian_electric_displacement_field] -> [electric_displacement_field]: value / (4 * π / ε_0) ** 0.5 - [electric_displacement_field] -> [gaussian_electric_displacement_field]: value * (4 * π / ε_0) ** 0.5 - [gaussian_electric_dipole] -> [electric_dipole]: value / k_C ** 0.5 - [electric_dipole] -> [gaussian_electric_dipole]: value * k_C ** 0.5 - [gaussian_electric_quadrupole] -> [electric_quadrupole]: value / k_C ** 0.5 - [electric_quadrupole] -> [gaussian_electric_quadrupole]: value * k_C ** 0.5 - [gaussian_magnetic_field] -> [magnetic_field]: value / (4 * π / µ_0) ** 0.5 - [magnetic_field] -> [gaussian_magnetic_field]: value * (4 * π / µ_0) ** 0.5 - [gaussian_magnetic_flux] -> [magnetic_flux]: value / (4 * π / µ_0) ** 0.5 - [magnetic_flux] -> [gaussian_magnetic_flux]: value * (4 * π / µ_0) ** 0.5 - [gaussian_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π * µ_0) ** 0.5 - [magnetic_field_strength] -> [gaussian_magnetic_field_strength]: value * (4 * π * µ_0) ** 0.5 - [gaussian_magnetic_dipole] -> [magnetic_dipole]: value * (4 * π / µ_0) ** 0.5 - [magnetic_dipole] -> [gaussian_magnetic_dipole]: value / (4 * π / µ_0) ** 0.5 - [gaussian_resistance] -> [resistance]: value * k_C - [resistance] -> [gaussian_resistance]: value / k_C - [gaussian_resistivity] -> [resistivity]: value * k_C - [resistivity] -> [gaussian_resistivity]: value / k_C - [gaussian_capacitance] -> [capacitance]: value / k_C - [capacitance] -> [gaussian_capacitance]: value * k_C - [gaussian_inductance] -> [inductance]: value * k_C - [inductance] -> [gaussian_inductance]: value / k_C - [gaussian_conductance] -> [conductance]: value / k_C - [conductance] -> [gaussian_conductance]: value * k_C -@end - -# === ESU system of units === -# (where different from Gaussian) -# See note for Gaussian system too -@group ESU using Gaussian - statweber = statvolt * second = statWb - stattesla = statweber / centimeter ** 2 = statT - stathenry = statweber / statampere = statH -@end -[esu_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] -[esu_current] = [esu_charge] / [time] -[esu_electric_potential] = [esu_charge] / [length] -[esu_magnetic_flux] = [esu_electric_potential] * [time] -[esu_magnetic_field] = [esu_magnetic_flux] / [area] -[esu_magnetic_field_strength] = [esu_current] / [length] -[esu_magnetic_dipole] = [esu_current] * [area] -@context ESU = esu - [esu_magnetic_field] -> [magnetic_field]: value * k_C ** 0.5 - [magnetic_field] -> [esu_magnetic_field]: value / k_C ** 0.5 - [esu_magnetic_flux] -> [magnetic_flux]: value * k_C ** 0.5 - [magnetic_flux] -> [esu_magnetic_flux]: value / k_C ** 0.5 - [esu_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π / ε_0) ** 0.5 - [magnetic_field_strength] -> [esu_magnetic_field_strength]: value * (4 * π / ε_0) ** 0.5 - [esu_magnetic_dipole] -> [magnetic_dipole]: value / k_C ** 0.5 - [magnetic_dipole] -> [esu_magnetic_dipole]: value * k_C ** 0.5 -@end - - -#### CONVERSION CONTEXTS #### - -@context(n=1) spectroscopy = sp - # n index of refraction of the medium. - [length] <-> [frequency]: speed_of_light / n / value - [frequency] -> [energy]: planck_constant * value - [energy] -> [frequency]: value / planck_constant - # allow wavenumber / kayser - [wavenumber] <-> [length]: 1 / value -@end - -@context boltzmann - [temperature] -> [energy]: boltzmann_constant * value - [energy] -> [temperature]: value / boltzmann_constant -@end - -@context energy - [energy] -> [energy] / [substance]: value * N_A - [energy] / [substance] -> [energy]: value / N_A - [energy] -> [mass]: value / c ** 2 - [mass] -> [energy]: value * c ** 2 -@end - -@context(mw=0,volume=0,solvent_mass=0) chemistry = chem - # mw is the molecular weight of the species - # volume is the volume of the solution - # solvent_mass is the mass of solvent in the solution - - # moles -> mass require the molecular weight - [substance] -> [mass]: value * mw - [mass] -> [substance]: value / mw - - # moles/volume -> mass/volume and moles/mass -> mass/mass - # require the molecular weight - [substance] / [volume] -> [mass] / [volume]: value * mw - [mass] / [volume] -> [substance] / [volume]: value / mw - [substance] / [mass] -> [mass] / [mass]: value * mw - [mass] / [mass] -> [substance] / [mass]: value / mw - - # moles/volume -> moles requires the solution volume - [substance] / [volume] -> [substance]: value * volume - [substance] -> [substance] / [volume]: value / volume - - # moles/mass -> moles requires the solvent (usually water) mass - [substance] / [mass] -> [substance]: value * solvent_mass - [substance] -> [substance] / [mass]: value / solvent_mass - - # moles/mass -> moles/volume require the solvent mass and the volume - [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume - [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume - -@end - -@context textile - # Allow switching between Direct count system (i.e. tex) and - # Indirect count system (i.e. Ne, Nm) - [mass] / [length] <-> [length] / [mass]: 1 / value -@end - - -#### SYSTEMS OF UNITS #### - -@system SI - second - meter - kilogram - ampere - kelvin - mole - candela -@end - -@system mks using international - meter - kilogram - second -@end - -@system cgs using international, Gaussian, ESU - centimeter - gram - second -@end - -@system atomic using international - # based on unit m_e, e, hbar, k_C, k - bohr: meter - electron_mass: gram - atomic_unit_of_time: second - atomic_unit_of_current: ampere - atomic_unit_of_temperature: kelvin -@end - -@system Planck using international - # based on unit c, gravitational_constant, hbar, k_C, k - planck_length: meter - planck_mass: gram - planck_time: second - planck_current: ampere - planck_temperature: kelvin -@end - -@system imperial using ImperialVolume, USCSLengthInternational, AvoirdupoisUK - yard - pound -@end - -@system US using USCSLiquidVolume, USCSDryVolume, USCSVolumeOther, USCSLengthInternational, USCSLengthSurvey, AvoirdupoisUS - yard - pound -@end - -pixel = 1 micrometer = px -xpixel = 1 micrometer = xpx -ypixel = 1 micrometer = ypx -zpixel = 1 micrometer = zpx -simulation_xpixel = 1 micrometer = sxpx -simulation_ypixel = 1 micrometer = sypx -simulation_zpixel = 1 micrometer = szpx -""" \ No newline at end of file From de65307c806b421f8c7b6f22357a0a88207216d5 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe Date: Mon, 9 Dec 2024 00:29:36 +0100 Subject: [PATCH 102/105] Create pint_definition.py --- deeptrack/backend/pint_definition.py | 994 +++++++++++++++++++++++++++ 1 file changed, 994 insertions(+) create mode 100644 deeptrack/backend/pint_definition.py diff --git a/deeptrack/backend/pint_definition.py b/deeptrack/backend/pint_definition.py new file mode 100644 index 000000000..1c75457b0 --- /dev/null +++ b/deeptrack/backend/pint_definition.py @@ -0,0 +1,994 @@ +"""Pint constants and units definition for DeepTrack2. + +This file consolidates and extends the default definitions provided by Pint's +`default_en.txt` and `constants_en.txt` files. These files define physical +constants and unit systems based on internationally recognized standards, such +as the International System of Units (SI), and additional systems like CGS, +Planck units, and atomic units. + +Sources: +-------- +- Pint's default unit definitions: + https://github.com/hgrecco/pint/blob/main/pint/default_en.txt +- Pint's default constants definitions: + https://github.com/hgrecco/pint/blob/main/pint/constants_en.txt + +Content: +-------- +- Mathematical Constants: Includes key values like π, Euler's number, + and the natural logarithm of 10. +- Physical Constants: Covers fundamental constants like the speed of light, + Planck constant, and Boltzmann constant. +- Derived Constants: Defines values such as the fine-structure constant and + classical electron radius. +- Units: Provides base and derived units for length, mass, time, energy, etc., + with precise conversion factors. +- Prefixes and Aliases: Defines standard prefixes (e.g., milli-, kilo-, mega-) + and unit aliases to ensure flexibility. +- Unit Systems: Details unit systems, including SI, MKS, CGS, Planck, and + imperial units. +- Contexts and Conversion: Includes context-specific definitions to facilitate + domain-specific conversions. + +Key Modifications: +------------------ +This file is derived from the default Pint files with the adjustments: +1. Groups Removed: Unit group definitions (e.g., `@group`) have been excluded + to avoid conflicts with the definition of pixel. +2. Final Variables Added: Defines constants and variables required for the + project-specific context (e.g., pixel-related units). + +Usage: +------ +To create a unit registry with custom pixel-related units: + +>>> from pint import UnitRegistry +>>> from .backend.pint_definition import pint_definitions +>>> +>>> units = UnitRegistry(pint_definitions.split("\n")) + +""" + + +pint_constants = """ +# Default Pint constants definition file +# Based on the International System of Units +# Language: english +# Source: https://physics.nist.gov/cuu/Constants/ +# https://physics.nist.gov/PhysRefData/XrayTrans/Html/search.html +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +#### MATHEMATICAL CONSTANTS #### +# As computed by Maxima with fpprec:50 + +pi = 3.1415926535897932384626433832795028841971693993751 = π # pi +tansec = 4.8481368111333441675396429478852851658848753880815e-6 # tangent of 1 arc-second ~ arc_second/radian +ln10 = 2.3025850929940456840179914546843642076011014886288 # natural logarithm of 10 +wien_x = 4.9651142317442763036987591313228939440555849867973 # solution to (x-5)*exp(x)+5 = 0 => x = W(5/exp(5))+5 +wien_u = 2.8214393721220788934031913302944851953458817440731 # solution to (u-3)*exp(u)+3 = 0 => u = W(3/exp(3))+3 +eulers_number = 2.71828182845904523536028747135266249775724709369995 + +#### DEFINED EXACT CONSTANTS #### + +speed_of_light = 299792458 m/s = c = c_0 # since 1983 +planck_constant = 6.62607015e-34 J s = h # since May 2019 +elementary_charge = 1.602176634e-19 C = e # since May 2019 +avogadro_number = 6.02214076e23 # since May 2019 +boltzmann_constant = 1.380649e-23 J K^-1 = k = k_B # since May 2019 +standard_gravity = 9.80665 m/s^2 = g_0 = g0 = g_n = gravity # since 1901 +standard_atmosphere = 1.01325e5 Pa = atm = atmosphere # since 1954 +conventional_josephson_constant = 4.835979e14 Hz / V = K_J90 # since Jan 1990 +conventional_von_klitzing_constant = 2.5812807e4 ohm = R_K90 # since Jan 1990 + +#### DERIVED EXACT CONSTANTS #### +# Floating-point conversion may introduce inaccuracies + +zeta = c / (cm/s) = ζ +dirac_constant = h / (2 * π) = ħ = hbar = atomic_unit_of_action = a_u_action +avogadro_constant = avogadro_number * mol^-1 = N_A +molar_gas_constant = k * N_A = R +faraday_constant = e * N_A +conductance_quantum = 2 * e ** 2 / h = G_0 +magnetic_flux_quantum = h / (2 * e) = Φ_0 = Phi_0 +josephson_constant = 2 * e / h = K_J +von_klitzing_constant = h / e ** 2 = R_K +stefan_boltzmann_constant = 2 / 15 * π ** 5 * k ** 4 / (h ** 3 * c ** 2) = σ = sigma +first_radiation_constant = 2 * π * h * c ** 2 = c_1 +second_radiation_constant = h * c / k = c_2 +wien_wavelength_displacement_law_constant = h * c / (k * wien_x) +wien_frequency_displacement_law_constant = wien_u * k / h + +#### MEASURED CONSTANTS #### +# Recommended CODATA-2018 values +# To some extent, what is measured and what is derived is a bit arbitrary. +# The choice of measured constants is based on convenience and on available uncertainty. +# The uncertainty in the last significant digits is given in parentheses as a comment. + +newtonian_constant_of_gravitation = 6.67430e-11 m^3/(kg s^2) = _ = gravitational_constant # (15) +rydberg_constant = 1.0973731568160e7 * m^-1 = R_∞ = R_inf # (21) +electron_g_factor = -2.00231930436256 = g_e # (35) +atomic_mass_constant = 1.66053906660e-27 kg = m_u # (50) +electron_mass = 9.1093837015e-31 kg = m_e = atomic_unit_of_mass = a_u_mass # (28) +proton_mass = 1.67262192369e-27 kg = m_p # (51) +neutron_mass = 1.67492749804e-27 kg = m_n # (95) +lattice_spacing_of_Si = 1.920155716e-10 m = d_220 # (32) +K_alpha_Cu_d_220 = 0.80232719 # (22) +K_alpha_Mo_d_220 = 0.36940604 # (19) +K_alpha_W_d_220 = 0.108852175 # (98) + +#### DERIVED CONSTANTS #### + +fine_structure_constant = (2 * h * R_inf / (m_e * c)) ** 0.5 = α = alpha +vacuum_permeability = 2 * α * h / (e ** 2 * c) = µ_0 = mu_0 = mu0 = magnetic_constant +vacuum_permittivity = e ** 2 / (2 * α * h * c) = ε_0 = epsilon_0 = eps_0 = eps0 = electric_constant +impedance_of_free_space = 2 * α * h / e ** 2 = Z_0 = characteristic_impedance_of_vacuum +coulomb_constant = α * hbar * c / e ** 2 = k_C +classical_electron_radius = α * hbar / (m_e * c) = r_e +thomson_cross_section = 8 / 3 * π * r_e ** 2 = σ_e = sigma_e +""" + +pint_definitions = f""" +# Default Pint units definition file +# Based on the International System of Units +# Language: english +# :copyright: 2013,2019 by Pint Authors, see AUTHORS for more details. + +# Syntax +# ====== +# Units +# ----- +# = [= ] [= ] [ = ] [...] +# +# The canonical name and aliases should be expressed in singular form. +# Pint automatically deals with plurals built by adding 's' to the singular form; plural +# forms that don't follow this rule should be instead explicitly listed as aliases. +# +# If a unit has no symbol and one wants to define aliases, then the symbol should be +# conventionally set to _. +# +# Example: +# millennium = 1e3 * year = _ = millennia +# +# +# Prefixes +# -------- +# - = [= ] [= ] [ = ] [...] +# +# Example: +# deca- = 1e+1 = da- = deka- +# +# +# Derived dimensions +# ------------------ +# [dimension name] = +# +# Example: +# [density] = [mass] / [volume] +# +# Note that primary dimensions don't need to be declared; they can be +# defined for the first time in a unit definition. +# E.g. see below `meter = [length]` +# +# +# Additional aliases +# ------------------ +# @alias = [ = ] [...] +# +# Used to add aliases to already existing unit definitions. +# Particularly useful when one wants to enrich definitions +# from defaults_en.txt with custom aliases. +# +# Example: +# @alias meter = my_meter + +# See also: https://pint.readthedocs.io/en/latest/defining.html + +@defaults + group = international + system = mks +@end + + +#### PREFIXES #### + +# decimal prefixes +yocto- = 1e-24 = y- +zepto- = 1e-21 = z- +atto- = 1e-18 = a- +femto- = 1e-15 = f- +pico- = 1e-12 = p- +nano- = 1e-9 = n- +micro- = 1e-6 = µ- = u- +milli- = 1e-3 = m- +centi- = 1e-2 = c- +deci- = 1e-1 = d- +deca- = 1e+1 = da- = deka- +hecto- = 1e2 = h- +kilo- = 1e3 = k- +mega- = 1e6 = M- +giga- = 1e9 = G- +tera- = 1e12 = T- +peta- = 1e15 = P- +exa- = 1e18 = E- +zetta- = 1e21 = Z- +yotta- = 1e24 = Y- + +# binary_prefixes +kibi- = 2**10 = Ki- +mebi- = 2**20 = Mi- +gibi- = 2**30 = Gi- +tebi- = 2**40 = Ti- +pebi- = 2**50 = Pi- +exbi- = 2**60 = Ei- +zebi- = 2**70 = Zi- +yobi- = 2**80 = Yi- + +# extra_prefixes +semi- = 0.5 = _ = demi- +sesqui- = 1.5 + + +#### BASE UNITS #### + +meter = [length] = m = metre +second = [time] = s = sec +ampere = [current] = A = amp +candela = [luminosity] = cd = candle +gram = [mass] = g +mole = [substance] = mol +kelvin = [temperature]; offset: 0 = K = degK = °K = degree_Kelvin = degreeK # older names supported for compatibility +radian = [] = rad +bit = [] +count = [] + + +#### CONSTANTS #### + +{pint_constants} + + +#### UNITS #### +# Common and less common, grouped by quantity. +# Conversion factors are exact (except when noted), +# although floating-point conversion may introduce inaccuracies + +# Angle +turn = 2 * π * radian = _ = revolution = cycle = circle +degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree +arcminute = degree / 60 = arcmin = arc_minute = angular_minute +arcsecond = arcminute / 60 = arcsec = arc_second = angular_second +milliarcsecond = 1e-3 * arcsecond = mas +grade = π / 200 * radian = grad = gon +mil = π / 32000 * radian + +# Solid angle +steradian = radian ** 2 = sr +square_degree = (π / 180) ** 2 * sr = sq_deg = sqdeg + +# Information +baud = bit / second = Bd = bps + +byte = 8 * bit = B = octet +# byte = 8 * bit = _ = octet +## NOTE: B (byte) symbol can conflict with Bell + +# Length +angstrom = 1e-10 * meter = Å = ångström = Å +micron = micrometer = µ +fermi = femtometer = fm +light_year = speed_of_light * julian_year = ly = lightyear +astronomical_unit = 149597870700 * meter = au # since Aug 2012 +parsec = 1 / tansec * astronomical_unit = pc +nautical_mile = 1852 * meter = nmi +bohr = hbar / (alpha * m_e * c) = a_0 = a0 = bohr_radius = atomic_unit_of_length = a_u_length +x_unit_Cu = K_alpha_Cu_d_220 * d_220 / 1537.4 = Xu_Cu +x_unit_Mo = K_alpha_Mo_d_220 * d_220 / 707.831 = Xu_Mo +angstrom_star = K_alpha_W_d_220 * d_220 / 0.2090100 = Å_star +planck_length = (hbar * gravitational_constant / c ** 3) ** 0.5 + +# Mass +metric_ton = 1e3 * kilogram = t = tonne +unified_atomic_mass_unit = atomic_mass_constant = u = amu +dalton = atomic_mass_constant = Da +grain = 64.79891 * milligram = gr +gamma_mass = microgram +carat = 200 * milligram = ct = karat +planck_mass = (hbar * c / gravitational_constant) ** 0.5 + +# Time +minute = 60 * second = min +hour = 60 * minute = hr +day = 24 * hour = d +week = 7 * day +fortnight = 2 * week +year = 365.25 * day = a = yr = julian_year +month = year / 12 + +# decade = 10 * year +## NOTE: decade [time] can conflict with decade [dimensionless] + +century = 100 * year = _ = centuries +millennium = 1e3 * year = _ = millennia +eon = 1e9 * year +shake = 1e-8 * second +svedberg = 1e-13 * second +atomic_unit_of_time = hbar / E_h = a_u_time +gregorian_year = 365.2425 * day +sidereal_year = 365.256363004 * day # approximate, as of J2000 epoch +tropical_year = 365.242190402 * day # approximate, as of J2000 epoch +common_year = 365 * day +leap_year = 366 * day +sidereal_day = day / 1.00273790935079524 # approximate +sidereal_month = 27.32166155 * day # approximate +tropical_month = 27.321582 * day # approximate +synodic_month = 29.530589 * day = _ = lunar_month # approximate +planck_time = (hbar * gravitational_constant / c ** 5) ** 0.5 + +# Temperature +degree_Celsius = kelvin; offset: 273.15 = °C = celsius = degC = degreeC +degree_Rankine = 5 / 9 * kelvin; offset: 0 = °R = rankine = degR = degreeR +degree_Fahrenheit = 5 / 9 * kelvin; offset: 233.15 + 200 / 9 = °F = fahrenheit = degF = degreeF +degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degreeRe = degree_Réaumur = réaumur +atomic_unit_of_temperature = E_h / k = a_u_temp +planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5 + +# Area +[area] = [length] ** 2 +are = 100 * meter ** 2 +barn = 1e-28 * meter ** 2 = b +darcy = centipoise * centimeter ** 2 / (second * atmosphere) +hectare = 100 * are = ha + +# Volume +[volume] = [length] ** 3 +liter = decimeter ** 3 = l = L = litre +cubic_centimeter = centimeter ** 3 = cc +lambda = microliter = λ +stere = meter ** 3 + +# Frequency +[frequency] = 1 / [time] +hertz = 1 / second = Hz +revolutions_per_minute = revolution / minute = rpm +revolutions_per_second = revolution / second = rps +counts_per_second = count / second = cps + +# Wavenumber +[wavenumber] = 1 / [length] +reciprocal_centimeter = 1 / cm = cm_1 = kayser + +# Velocity +[velocity] = [length] / [time] +[speed] = [velocity] +knot = nautical_mile / hour = kt = knot_international = international_knot +mile_per_hour = mile / hour = mph = MPH +kilometer_per_hour = kilometer / hour = kph = KPH +kilometer_per_second = kilometer / second = kps +meter_per_second = meter / second = mps +foot_per_second = foot / second = fps + +# Acceleration +[acceleration] = [velocity] / [time] +galileo = centimeter / second ** 2 = Gal + +# Force +[force] = [mass] * [acceleration] +newton = kilogram * meter / second ** 2 = N +dyne = gram * centimeter / second ** 2 = dyn +force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond +force_gram = g_0 * gram = gf = gram_force +force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force +atomic_unit_of_force = E_h / a_0 = a_u_force + +# Energy +[energy] = [force] * [length] +joule = newton * meter = J +erg = dyne * centimeter +watt_hour = watt * hour = Wh = watthour +electron_volt = e * volt = eV +rydberg = h * c * R_inf = Ry +hartree = 2 * rydberg = E_h = Eh = hartree_energy = atomic_unit_of_energy = a_u_energy +calorie = 4.184 * joule = cal = thermochemical_calorie = cal_th +international_calorie = 4.1868 * joule = cal_it = international_steam_table_calorie +fifteen_degree_calorie = 4.1855 * joule = cal_15 +british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso +international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it +thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th +quadrillion_Btu = 1e15 * Btu = quad +therm = 1e5 * Btu = thm = EC_therm +US_therm = 1.054804e8 * joule # approximate, no exact definition +ton_TNT = 1e9 * calorie = tTNT +tonne_of_oil_equivalent = 1e10 * international_calorie = toe +atmosphere_liter = atmosphere * liter = atm_l + +# Power +[power] = [energy] / [time] +watt = joule / second = W +volt_ampere = volt * ampere = VA +horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower +boiler_horsepower = 33475 * Btu / hour # unclear which Btu +metric_horsepower = 75 * force_kilogram * meter / second +electrical_horsepower = 746 * watt +refrigeration_ton = 12e3 * Btu / hour = _ = ton_of_refrigeration # approximate, no exact definition +standard_liter_per_minute = atmosphere * liter / minute = slpm = slm +conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90 + +# Momentum +[momentum] = [length] * [mass] / [time] + +# Density (as auxiliary for pressure) +[density] = [mass] / [volume] +mercury = 13.5951 * kilogram / liter = Hg = Hg_0C = Hg_32F = conventional_mercury +water = 1.0 * kilogram / liter = H2O = conventional_water +mercury_60F = 13.5568 * kilogram / liter = Hg_60F # approximate +water_39F = 0.999972 * kilogram / liter = water_4C # approximate +water_60F = 0.999001 * kilogram / liter # approximate + +# Pressure +[pressure] = [force] / [area] +pascal = newton / meter ** 2 = Pa +barye = dyne / centimeter ** 2 = Ba = barie = barad = barrie = baryd +bar = 1e5 * pascal +technical_atmosphere = kilogram * g_0 / centimeter ** 2 = at +torr = atm / 760 +pound_force_per_square_inch = force_pound / inch ** 2 = psi +kip_per_square_inch = kip / inch ** 2 = ksi +millimeter_Hg = millimeter * Hg * g_0 = mmHg = mm_Hg = millimeter_Hg_0C +centimeter_Hg = centimeter * Hg * g_0 = cmHg = cm_Hg = centimeter_Hg_0C +inch_Hg = inch * Hg * g_0 = inHg = in_Hg = inch_Hg_32F +inch_Hg_60F = inch * Hg_60F * g_0 +inch_H2O_39F = inch * water_39F * g_0 +inch_H2O_60F = inch * water_60F * g_0 +foot_H2O = foot * water * g_0 = ftH2O = feet_H2O +centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O +sound_pressure_level = 20e-6 * pascal = SPL + +# Torque +[torque] = [force] * [length] +foot_pound = foot * force_pound = ft_lb = footpound + +# Viscosity +[viscosity] = [pressure] * [time] +poise = 0.1 * Pa * second = P +reyn = psi * second + +# Kinematic viscosity +[kinematic_viscosity] = [area] / [time] +stokes = centimeter ** 2 / second = St + +# Fluidity +[fluidity] = 1 / [viscosity] +rhe = 1 / poise + +# Amount of substance +particle = 1 / N_A = _ = molec = molecule + +# Concentration +[concentration] = [substance] / [volume] +molar = mole / liter = M + +# Catalytic activity +[activity] = [substance] / [time] +katal = mole / second = kat +enzyme_unit = micromole / minute = U = enzymeunit + +# Entropy +[entropy] = [energy] / [temperature] +clausius = calorie / kelvin = Cl + +# Molar entropy +[molar_entropy] = [entropy] / [substance] +entropy_unit = calorie / kelvin / mole = eu + +# Radiation +becquerel = counts_per_second = Bq +curie = 3.7e10 * becquerel = Ci +rutherford = 1e6 * becquerel = Rd +gray = joule / kilogram = Gy +sievert = joule / kilogram = Sv +rads = 0.01 * gray +rem = 0.01 * sievert +roentgen = 2.58e-4 * coulomb / kilogram = _ = röntgen # approximate, depends on medium + +# Heat transimission +[heat_transmission] = [energy] / [area] +peak_sun_hour = 1e3 * watt_hour / meter ** 2 = PSH +langley = thermochemical_calorie / centimeter ** 2 = Ly + +# Luminance +[luminance] = [luminosity] / [area] +nit = candela / meter ** 2 +stilb = candela / centimeter ** 2 +lambert = 1 / π * candela / centimeter ** 2 + +# Luminous flux +[luminous_flux] = [luminosity] +lumen = candela * steradian = lm + +# Illuminance +[illuminance] = [luminous_flux] / [area] +lux = lumen / meter ** 2 = lx + +# Intensity +[intensity] = [power] / [area] +atomic_unit_of_intensity = 0.5 * ε_0 * c * atomic_unit_of_electric_field ** 2 = a_u_intensity + +# Current +biot = 10 * ampere = Bi +abampere = biot = abA +atomic_unit_of_current = e / atomic_unit_of_time = a_u_current +mean_international_ampere = mean_international_volt / mean_international_ohm = A_it +US_international_ampere = US_international_volt / US_international_ohm = A_US +conventional_ampere_90 = K_J90 * R_K90 / (K_J * R_K) * ampere = A_90 +planck_current = (c ** 6 / gravitational_constant / k_C) ** 0.5 + +# Charge +[charge] = [current] * [time] +coulomb = ampere * second = C +abcoulomb = 10 * C = abC +faraday = e * N_A * mole +conventional_coulomb_90 = K_J90 * R_K90 / (K_J * R_K) * coulomb = C_90 +ampere_hour = ampere * hour = Ah + +# Electric potential +[electric_potential] = [energy] / [charge] +volt = joule / coulomb = V +abvolt = 1e-8 * volt = abV +mean_international_volt = 1.00034 * volt = V_it # approximate +US_international_volt = 1.00033 * volt = V_US # approximate +conventional_volt_90 = K_J90 / K_J * volt = V_90 + +# Electric field +[electric_field] = [electric_potential] / [length] +atomic_unit_of_electric_field = e * k_C / a_0 ** 2 = a_u_electric_field + +# Electric displacement field +[electric_displacement_field] = [charge] / [area] + +# Resistance +[resistance] = [electric_potential] / [current] +ohm = volt / ampere = Ω +abohm = 1e-9 * ohm = abΩ +mean_international_ohm = 1.00049 * ohm = Ω_it = ohm_it # approximate +US_international_ohm = 1.000495 * ohm = Ω_US = ohm_US # approximate +conventional_ohm_90 = R_K / R_K90 * ohm = Ω_90 = ohm_90 + +# Resistivity +[resistivity] = [resistance] * [length] + +# Conductance +[conductance] = [current] / [electric_potential] +siemens = ampere / volt = S = mho +absiemens = 1e9 * siemens = abS = abmho + +# Capacitance +[capacitance] = [charge] / [electric_potential] +farad = coulomb / volt = F +abfarad = 1e9 * farad = abF +conventional_farad_90 = R_K90 / R_K * farad = F_90 + +# Inductance +[inductance] = [magnetic_flux] / [current] +henry = weber / ampere = H +abhenry = 1e-9 * henry = abH +conventional_henry_90 = R_K / R_K90 * henry = H_90 + +# Magnetic flux +[magnetic_flux] = [electric_potential] * [time] +weber = volt * second = Wb +unit_pole = µ_0 * biot * centimeter + +# Magnetic field +[magnetic_field] = [magnetic_flux] / [area] +tesla = weber / meter ** 2 = T +gamma = 1e-9 * tesla = γ + +# Magnetomotive force +[magnetomotive_force] = [current] +ampere_turn = ampere = At +biot_turn = biot +gilbert = 1 / (4 * π) * biot_turn = Gb + +# Magnetic field strength +[magnetic_field_strength] = [current] / [length] + +# Electric dipole moment +[electric_dipole] = [charge] * [length] +debye = 1e-9 / ζ * coulomb * angstrom = D # formally 1 D = 1e-10 Fr*Å, but we generally want to use it outside the Gaussian context + +# Electric quadrupole moment +[electric_quadrupole] = [charge] * [area] +buckingham = debye * angstrom + +# Magnetic dipole moment +[magnetic_dipole] = [current] * [area] +bohr_magneton = e * hbar / (2 * m_e) = µ_B = mu_B +nuclear_magneton = e * hbar / (2 * m_p) = µ_N = mu_N + +# Logaritmic Unit Definition +# Unit = scale; logbase; logfactor +# x_dB = [logfactor] * log( x_lin / [scale] ) / log( [logbase] ) + +# Logaritmic Units of dimensionless quantity: [ https://en.wikipedia.org/wiki/Level_(logarithmic_quantity) ] + +decibelmilliwatt = 1e-3 watt; logbase: 10; logfactor: 10 = dBm +decibelmicrowatt = 1e-6 watt; logbase: 10; logfactor: 10 = dBu + +decibel = 1 ; logbase: 10; logfactor: 10 = dB +# bell = 1 ; logbase: 10; logfactor: = B +## NOTE: B (Bell) symbol conflicts with byte + +decade = 1 ; logbase: 10; logfactor: 1 +## NOTE: decade [time] can conflict with decade [dimensionless] + +octave = 1 ; logbase: 2; logfactor: 1 = oct + +neper = 1 ; logbase: 2.71828182845904523536028747135266249775724709369995; logfactor: 0.5 = Np +# neper = 1 ; logbase: eulers_number; logfactor: 0.5 = Np + +#### UNIT GROUPS #### +# Mostly for length, area, volume, mass, force +# (customary or specialized units) + +@group USCSLengthInternational + thou = 1e-3 * inch = th = mil_length + inch = yard / 36 = in = international_inch = inches = international_inches + hand = 4 * inch + foot = yard / 3 = ft = international_foot = feet = international_feet + yard = 0.9144 * meter = yd = international_yard # since Jul 1959 + mile = 1760 * yard = mi = international_mile + + circular_mil = π / 4 * mil_length ** 2 = cmil + square_inch = inch ** 2 = sq_in = square_inches + square_foot = foot ** 2 = sq_ft = square_feet + square_yard = yard ** 2 = sq_yd + square_mile = mile ** 2 = sq_mi + + cubic_inch = in ** 3 = cu_in + cubic_foot = ft ** 3 = cu_ft = cubic_feet + cubic_yard = yd ** 3 = cu_yd +@end + +@group USCSLengthSurvey + link = 1e-2 * chain = li = survey_link + survey_foot = 1200 / 3937 * meter = sft + fathom = 6 * survey_foot + rod = 16.5 * survey_foot = rd = pole = perch + chain = 4 * rod + furlong = 40 * rod = fur + cables_length = 120 * fathom + survey_mile = 5280 * survey_foot = smi = us_statute_mile + league = 3 * survey_mile + + square_rod = rod ** 2 = sq_rod = sq_pole = sq_perch + acre = 10 * chain ** 2 + square_survey_mile = survey_mile ** 2 = _ = section + square_league = league ** 2 + + acre_foot = acre * survey_foot = _ = acre_feet +@end + +@group USCSDryVolume + dry_pint = bushel / 64 = dpi = US_dry_pint + dry_quart = bushel / 32 = dqt = US_dry_quart + dry_gallon = bushel / 8 = dgal = US_dry_gallon + peck = bushel / 4 = pk + bushel = 2150.42 cubic_inch = bu + dry_barrel = 7056 cubic_inch = _ = US_dry_barrel + board_foot = ft * ft * in = FBM = board_feet = BF = BDFT = super_foot = superficial_foot = super_feet = superficial_feet +@end + +@group USCSLiquidVolume + minim = pint / 7680 + fluid_dram = pint / 128 = fldr = fluidram = US_fluid_dram = US_liquid_dram + fluid_ounce = pint / 16 = floz = US_fluid_ounce = US_liquid_ounce + gill = pint / 4 = gi = liquid_gill = US_liquid_gill + pint = quart / 2 = pt = liquid_pint = US_pint + fifth = gallon / 5 = _ = US_liquid_fifth + quart = gallon / 4 = qt = liquid_quart = US_liquid_quart + gallon = 231 * cubic_inch = gal = liquid_gallon = US_liquid_gallon +@end + +@group USCSVolumeOther + teaspoon = fluid_ounce / 6 = tsp + tablespoon = fluid_ounce / 2 = tbsp + shot = 3 * tablespoon = jig = US_shot + cup = pint / 2 = cp = liquid_cup = US_liquid_cup + barrel = 31.5 * gallon = bbl + oil_barrel = 42 * gallon = oil_bbl + beer_barrel = 31 * gallon = beer_bbl + hogshead = 63 * gallon +@end + +@group Avoirdupois + dram = pound / 256 = dr = avoirdupois_dram = avdp_dram = drachm + ounce = pound / 16 = oz = avoirdupois_ounce = avdp_ounce + pound = 7e3 * grain = lb = avoirdupois_pound = avdp_pound + stone = 14 * pound + quarter = 28 * stone + bag = 94 * pound + hundredweight = 100 * pound = cwt = short_hundredweight + long_hundredweight = 112 * pound + ton = 2e3 * pound = _ = short_ton + long_ton = 2240 * pound + slug = g_0 * pound * second ** 2 / foot + slinch = g_0 * pound * second ** 2 / inch = blob = slugette + + force_ounce = g_0 * ounce = ozf = ounce_force + force_pound = g_0 * pound = lbf = pound_force + force_ton = g_0 * ton = _ = ton_force = force_short_ton = short_ton_force + force_long_ton = g_0 * long_ton = _ = long_ton_force + kip = 1e3 * force_pound + poundal = pound * foot / second ** 2 = pdl +@end + +@group AvoirdupoisUK using Avoirdupois + UK_hundredweight = long_hundredweight = UK_cwt + UK_ton = long_ton + UK_force_ton = force_long_ton = _ = UK_ton_force +@end + +@group AvoirdupoisUS using Avoirdupois + US_hundredweight = hundredweight = US_cwt + US_ton = ton + US_force_ton = force_ton = _ = US_ton_force +@end + +@group Troy + pennyweight = 24 * grain = dwt + troy_ounce = 480 * grain = toz = ozt + troy_pound = 12 * troy_ounce = tlb = lbt +@end + +@group Apothecary + scruple = 20 * grain + apothecary_dram = 3 * scruple = ap_dr + apothecary_ounce = 8 * apothecary_dram = ap_oz + apothecary_pound = 12 * apothecary_ounce = ap_lb +@end + +@group ImperialVolume + imperial_minim = imperial_fluid_ounce / 480 + imperial_fluid_scruple = imperial_fluid_ounce / 24 + imperial_fluid_drachm = imperial_fluid_ounce / 8 = imperial_fldr = imperial_fluid_dram + imperial_fluid_ounce = imperial_pint / 20 = imperial_floz = UK_fluid_ounce + imperial_gill = imperial_pint / 4 = imperial_gi = UK_gill + imperial_cup = imperial_pint / 2 = imperial_cp = UK_cup + imperial_pint = imperial_gallon / 8 = imperial_pt = UK_pint + imperial_quart = imperial_gallon / 4 = imperial_qt = UK_quart + imperial_gallon = 4.54609 * liter = imperial_gal = UK_gallon + imperial_peck = 2 * imperial_gallon = imperial_pk = UK_pk + imperial_bushel = 8 * imperial_gallon = imperial_bu = UK_bushel + imperial_barrel = 36 * imperial_gallon = imperial_bbl = UK_bbl +@end + +@group Textile + tex = gram / kilometer = Tt + dtex = decitex + denier = gram / (9 * kilometer) = den = Td + jute = pound / (14400 * yard) = Tj + aberdeen = jute = Ta + RKM = gf / tex + + number_english = 840 * yard / pound = Ne = NeC = ECC + number_meter = kilometer / kilogram = Nm +@end + + +#### CGS ELECTROMAGNETIC UNITS #### + +# === Gaussian system of units === +@group Gaussian + franklin = erg ** 0.5 * centimeter ** 0.5 = Fr = statcoulomb = statC = esu + statvolt = erg / franklin = statV + statampere = franklin / second = statA + gauss = dyne / franklin = G + maxwell = gauss * centimeter ** 2 = Mx + oersted = dyne / maxwell = Oe = ørsted + statohm = statvolt / statampere = statΩ + statfarad = franklin / statvolt = statF + statmho = statampere / statvolt +@end +# Note this system is not commensurate with SI, as ε_0 and µ_0 disappear; +# some quantities with different dimensions in SI have the same +# dimensions in the Gaussian system (e.g. [Mx] = [Fr], but [Wb] != [C]), +# and therefore the conversion factors depend on the context (not in pint sense) +[gaussian_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[gaussian_current] = [gaussian_charge] / [time] +[gaussian_electric_potential] = [gaussian_charge] / [length] +[gaussian_electric_field] = [gaussian_electric_potential] / [length] +[gaussian_electric_displacement_field] = [gaussian_charge] / [area] +[gaussian_electric_flux] = [gaussian_charge] +[gaussian_electric_dipole] = [gaussian_charge] * [length] +[gaussian_electric_quadrupole] = [gaussian_charge] * [area] +[gaussian_magnetic_field] = [force] / [gaussian_charge] +[gaussian_magnetic_field_strength] = [gaussian_magnetic_field] +[gaussian_magnetic_flux] = [gaussian_magnetic_field] * [area] +[gaussian_magnetic_dipole] = [energy] / [gaussian_magnetic_field] +[gaussian_resistance] = [gaussian_electric_potential] / [gaussian_current] +[gaussian_resistivity] = [gaussian_resistance] * [length] +[gaussian_capacitance] = [gaussian_charge] / [gaussian_electric_potential] +[gaussian_inductance] = [gaussian_electric_potential] * [time] / [gaussian_current] +[gaussian_conductance] = [gaussian_current] / [gaussian_electric_potential] +@context Gaussian = Gau + [gaussian_charge] -> [charge]: value / k_C ** 0.5 + [charge] -> [gaussian_charge]: value * k_C ** 0.5 + [gaussian_current] -> [current]: value / k_C ** 0.5 + [current] -> [gaussian_current]: value * k_C ** 0.5 + [gaussian_electric_potential] -> [electric_potential]: value * k_C ** 0.5 + [electric_potential] -> [gaussian_electric_potential]: value / k_C ** 0.5 + [gaussian_electric_field] -> [electric_field]: value * k_C ** 0.5 + [electric_field] -> [gaussian_electric_field]: value / k_C ** 0.5 + [gaussian_electric_displacement_field] -> [electric_displacement_field]: value / (4 * π / ε_0) ** 0.5 + [electric_displacement_field] -> [gaussian_electric_displacement_field]: value * (4 * π / ε_0) ** 0.5 + [gaussian_electric_dipole] -> [electric_dipole]: value / k_C ** 0.5 + [electric_dipole] -> [gaussian_electric_dipole]: value * k_C ** 0.5 + [gaussian_electric_quadrupole] -> [electric_quadrupole]: value / k_C ** 0.5 + [electric_quadrupole] -> [gaussian_electric_quadrupole]: value * k_C ** 0.5 + [gaussian_magnetic_field] -> [magnetic_field]: value / (4 * π / µ_0) ** 0.5 + [magnetic_field] -> [gaussian_magnetic_field]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_flux] -> [magnetic_flux]: value / (4 * π / µ_0) ** 0.5 + [magnetic_flux] -> [gaussian_magnetic_flux]: value * (4 * π / µ_0) ** 0.5 + [gaussian_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π * µ_0) ** 0.5 + [magnetic_field_strength] -> [gaussian_magnetic_field_strength]: value * (4 * π * µ_0) ** 0.5 + [gaussian_magnetic_dipole] -> [magnetic_dipole]: value * (4 * π / µ_0) ** 0.5 + [magnetic_dipole] -> [gaussian_magnetic_dipole]: value / (4 * π / µ_0) ** 0.5 + [gaussian_resistance] -> [resistance]: value * k_C + [resistance] -> [gaussian_resistance]: value / k_C + [gaussian_resistivity] -> [resistivity]: value * k_C + [resistivity] -> [gaussian_resistivity]: value / k_C + [gaussian_capacitance] -> [capacitance]: value / k_C + [capacitance] -> [gaussian_capacitance]: value * k_C + [gaussian_inductance] -> [inductance]: value * k_C + [inductance] -> [gaussian_inductance]: value / k_C + [gaussian_conductance] -> [conductance]: value / k_C + [conductance] -> [gaussian_conductance]: value * k_C +@end + +# === ESU system of units === +# (where different from Gaussian) +# See note for Gaussian system too +@group ESU using Gaussian + statweber = statvolt * second = statWb + stattesla = statweber / centimeter ** 2 = statT + stathenry = statweber / statampere = statH +@end +[esu_charge] = [length] ** 1.5 * [mass] ** 0.5 / [time] +[esu_current] = [esu_charge] / [time] +[esu_electric_potential] = [esu_charge] / [length] +[esu_magnetic_flux] = [esu_electric_potential] * [time] +[esu_magnetic_field] = [esu_magnetic_flux] / [area] +[esu_magnetic_field_strength] = [esu_current] / [length] +[esu_magnetic_dipole] = [esu_current] * [area] +@context ESU = esu + [esu_magnetic_field] -> [magnetic_field]: value * k_C ** 0.5 + [magnetic_field] -> [esu_magnetic_field]: value / k_C ** 0.5 + [esu_magnetic_flux] -> [magnetic_flux]: value * k_C ** 0.5 + [magnetic_flux] -> [esu_magnetic_flux]: value / k_C ** 0.5 + [esu_magnetic_field_strength] -> [magnetic_field_strength]: value / (4 * π / ε_0) ** 0.5 + [magnetic_field_strength] -> [esu_magnetic_field_strength]: value * (4 * π / ε_0) ** 0.5 + [esu_magnetic_dipole] -> [magnetic_dipole]: value / k_C ** 0.5 + [magnetic_dipole] -> [esu_magnetic_dipole]: value * k_C ** 0.5 +@end + + +#### CONVERSION CONTEXTS #### + +@context(n=1) spectroscopy = sp + # n index of refraction of the medium. + [length] <-> [frequency]: speed_of_light / n / value + [frequency] -> [energy]: planck_constant * value + [energy] -> [frequency]: value / planck_constant + # allow wavenumber / kayser + [wavenumber] <-> [length]: 1 / value +@end + +@context boltzmann + [temperature] -> [energy]: boltzmann_constant * value + [energy] -> [temperature]: value / boltzmann_constant +@end + +@context energy + [energy] -> [energy] / [substance]: value * N_A + [energy] / [substance] -> [energy]: value / N_A + [energy] -> [mass]: value / c ** 2 + [mass] -> [energy]: value * c ** 2 +@end + +@context(mw=0,volume=0,solvent_mass=0) chemistry = chem + # mw is the molecular weight of the species + # volume is the volume of the solution + # solvent_mass is the mass of solvent in the solution + + # moles -> mass require the molecular weight + [substance] -> [mass]: value * mw + [mass] -> [substance]: value / mw + + # moles/volume -> mass/volume and moles/mass -> mass/mass + # require the molecular weight + [substance] / [volume] -> [mass] / [volume]: value * mw + [mass] / [volume] -> [substance] / [volume]: value / mw + [substance] / [mass] -> [mass] / [mass]: value * mw + [mass] / [mass] -> [substance] / [mass]: value / mw + + # moles/volume -> moles requires the solution volume + [substance] / [volume] -> [substance]: value * volume + [substance] -> [substance] / [volume]: value / volume + + # moles/mass -> moles requires the solvent (usually water) mass + [substance] / [mass] -> [substance]: value * solvent_mass + [substance] -> [substance] / [mass]: value / solvent_mass + + # moles/mass -> moles/volume require the solvent mass and the volume + [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume + [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume + +@end + +@context textile + # Allow switching between Direct count system (i.e. tex) and + # Indirect count system (i.e. Ne, Nm) + [mass] / [length] <-> [length] / [mass]: 1 / value +@end + + +#### SYSTEMS OF UNITS #### + +@system SI + second + meter + kilogram + ampere + kelvin + mole + candela +@end + +@system mks using international + meter + kilogram + second +@end + +@system cgs using international, Gaussian, ESU + centimeter + gram + second +@end + +@system atomic using international + # based on unit m_e, e, hbar, k_C, k + bohr: meter + electron_mass: gram + atomic_unit_of_time: second + atomic_unit_of_current: ampere + atomic_unit_of_temperature: kelvin +@end + +@system Planck using international + # based on unit c, gravitational_constant, hbar, k_C, k + planck_length: meter + planck_mass: gram + planck_time: second + planck_current: ampere + planck_temperature: kelvin +@end + +@system imperial using ImperialVolume, USCSLengthInternational, AvoirdupoisUK + yard + pound +@end + +@system US using USCSLiquidVolume, USCSDryVolume, USCSVolumeOther, USCSLengthInternational, USCSLengthSurvey, AvoirdupoisUS + yard + pound +@end + +pixel = 1 micrometer = px +xpixel = 1 micrometer = xpx +ypixel = 1 micrometer = ypx +zpixel = 1 micrometer = zpx +simulation_xpixel = 1 micrometer = sxpx +simulation_ypixel = 1 micrometer = sypx +simulation_zpixel = 1 micrometer = szpx +""" \ No newline at end of file From 5f9a73f47bdfdaae5dbca46bbbcf3559ec9794f6 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe <46021832+giovannivolpe@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:50:53 +0100 Subject: [PATCH 103/105] Update ci.yml --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b02a0032f..c79bebb90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, macos-latest, windows-latest] install-deeplay: ["", "deeplay"] @@ -30,7 +30,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install flake8 - python -m pip install -r requirements.txt + python -m pip install -e . - name: Install deeplay if: ${{ matrix.install-deeplay == 'deeplay' }} run: | From d0b0f8155b356a3be1d9f251a6162e47ab4df4c1 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe <46021832+giovannivolpe@users.noreply.github.com> Date: Tue, 10 Dec 2024 16:52:35 +0100 Subject: [PATCH 104/105] Delete deeptrack/benchmarks directory --- deeptrack/benchmarks/test_arithmetics.py | 41 -------------------- deeptrack/benchmarks/test_fluorescence.py | 47 ----------------------- deeptrack/benchmarks/test_image.py | 43 --------------------- deeptrack/benchmarks/test_simulate_mie.py | 41 -------------------- 4 files changed, 172 deletions(-) delete mode 100644 deeptrack/benchmarks/test_arithmetics.py delete mode 100644 deeptrack/benchmarks/test_fluorescence.py delete mode 100644 deeptrack/benchmarks/test_image.py delete mode 100644 deeptrack/benchmarks/test_simulate_mie.py diff --git a/deeptrack/benchmarks/test_arithmetics.py b/deeptrack/benchmarks/test_arithmetics.py deleted file mode 100644 index 53185dcca..000000000 --- a/deeptrack/benchmarks/test_arithmetics.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import numpy as np -import itertools -import deeptrack as dt -import pytest -import itertools - - -u = dt.units - - -def create_pipeline(elements=1024): - - value = dt.Value(np.zeros((elements,))) - - value = value + 14 - - value = value * (np.ones((elements,)) * 2) - - value = value / 1.5 - - value = value ** 2 - - return value - - -@pytest.mark.parametrize( - "elements,gpu", - [*itertools.product((1000, 5000, 10000, 50000, 100000, 500000), [True, False])], -) -def test_arithmetic(elements, gpu, benchmark): - benchmark.group = "arithm_{}_elements".format(elements) - benchmark.name = "test_arithmetic_{}".format("gpu" if gpu else "cpu") - if gpu: - dt.config.enable_gpu() - else: - dt.config.disable_gpu() - pipeline = create_pipeline(elements=elements) - benchmark( - lambda: pipeline.update()(), - ) diff --git a/deeptrack/benchmarks/test_fluorescence.py b/deeptrack/benchmarks/test_fluorescence.py deleted file mode 100644 index 0b8766629..000000000 --- a/deeptrack/benchmarks/test_fluorescence.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys -import numpy as np -import itertools -import deeptrack as dt -import pytest - - -u = dt.units - - -def create_pipeline(output_region=(0, 0, 128, 128), num_particles=1): - - optics = dt.Fluorescence(output_region=output_region) - - mie = dt.Sphere( - radius=2e-6, - refractive_index=1.45, - z=10, - position=lambda: output_region[2:] * np.random.randn(2), - ) - - field = optics(mie ^ num_particles) - return field - - -@pytest.mark.parametrize( - "size,gpu", - [ - *itertools.product( - (64, 256, 512), - [True, False], - ) - ], -) -def test_simulate_mie(size, gpu, benchmark): - benchmark.group = f"fluorescence_{size}_px_image" - benchmark.name = f"test_fluorescence_{'gpu' if gpu else 'cpu'}" - if gpu: - dt.config.enable_gpu() - else: - dt.config.disable_gpu() - pipeline = create_pipeline(output_region=(0, 0, size, size), num_particles=1) - # One cold run for performance - pipeline.update()() - benchmark( - lambda: pipeline.update()(), - ) diff --git a/deeptrack/benchmarks/test_image.py b/deeptrack/benchmarks/test_image.py deleted file mode 100644 index 34c96a2a3..000000000 --- a/deeptrack/benchmarks/test_image.py +++ /dev/null @@ -1,43 +0,0 @@ -import sys -import numpy as np -import itertools -import deeptrack as dt -import pytest -import itertools -from deeptrack.backend._config import cupy as cp - -u = dt.units - - -def create_pipeline(elements=1024): - value = dt.Value(np.zeros((elements,))) - value = value + 14 - value = value * (np.ones((elements,)) * 2) - value = value / 1.5 - value = value ** 2 - return value - - -@pytest.mark.parametrize( - "elements,gpu,image", - [*itertools.product((1000, 10000, 100000, 1000000), [True, False], [True, False])], -) -def test_arithmetic(elements, gpu, image, benchmark): - benchmark.group = "add_{}_elements".format(elements) - benchmark.name = "test_{}_{}".format( - "Image" if image else "array", "gpu" if gpu else "cpu" - ) - - a = np.random.randn(elements) - b = np.random.randn(elements) - - if gpu: - a = cp.array(a) - b = cp.array(b) - if image: - a = dt.image.Image(a) - b = dt.image.Image(b) - - benchmark( - lambda: a + b, - ) diff --git a/deeptrack/benchmarks/test_simulate_mie.py b/deeptrack/benchmarks/test_simulate_mie.py deleted file mode 100644 index 51f60ee89..000000000 --- a/deeptrack/benchmarks/test_simulate_mie.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import numpy as np -import itertools -import deeptrack as dt -import pytest - - -u = dt.units - - -def create_pipeline(output_region=(0, 0, 128, 128), num_particles=1): - - optics = dt.Brightfield(output_region=output_region) - - mie = dt.MieSphere( - radius=0.5e-6, - refractive_index=1.45, - z=lambda: np.random.randn() * 10, - position=lambda: output_region[2:] * np.random.randn(2), - L=20, - ) - - field = optics(mie ^ num_particles) - return field - - -@pytest.mark.parametrize( - "size,gpu", - [*itertools.product((64, 128, 256, 512, 728), [True, False])], -) -def test_simulate_mie(size, gpu, benchmark): - benchmark.group = "mie_{}_px_image".format(size) - benchmark.name = "test_simulate_mie_{}".format("gpu" if gpu else "cpu") - if gpu: - dt.config.enable_gpu() - else: - dt.config.disable_gpu() - pipeline = create_pipeline(output_region=(0, 0, size, size), num_particles=2) - benchmark( - lambda: pipeline.update()(), - ) From f8e1669a9af9893787e8a7cd04fb3553f51aa8f3 Mon Sep 17 00:00:00 2001 From: Giovanni Volpe <46021832+giovannivolpe@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:25:01 +0100 Subject: [PATCH 105/105] u --- deeptrack/test/test_utils.py | 2 +- deeptrack/types.py | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/deeptrack/test/test_utils.py b/deeptrack/test/test_utils.py index 7e22238a4..f16285bd2 100644 --- a/deeptrack/test/test_utils.py +++ b/deeptrack/test/test_utils.py @@ -14,7 +14,7 @@ class TestUtils(unittest.TestCase): - def test_hasmethod(self): + def test_hasmethod(self): self.assertTrue(utils.hasmethod(utils, "hasmethod")) self.assertFalse( utils.hasmethod(utils, "this_is_definetely_not_a_method_of_utils") diff --git a/deeptrack/types.py b/deeptrack/types.py index 13fdf8375..fd9ad1314 100644 --- a/deeptrack/types.py +++ b/deeptrack/types.py @@ -8,15 +8,10 @@ """ -This module defines type aliases and utility types to standardize the type -annotations used throughout the codebase. It enhances code readability, -maintainability, and reduces redundancy in type annotations. These types are -particularly useful for properties and array-like structures used within the -library. -""" +import typing import numpy as np -import typing + # T is a generic type variable defining generic types for reusability. T = typing.TypeVar("T")