dkist-processing-math 2.1.2__tar.gz → 2.2.0rc1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/PKG-INFO +2 -2
  2. dkist_processing_math-2.2.0rc1/bitbucket-pipelines.yml +72 -0
  3. dkist_processing_math-2.2.0rc1/changelog/18.misc.rst +1 -0
  4. dkist_processing_math-2.2.0rc1/changelog/19.misc.rst +1 -0
  5. dkist_processing_math-2.2.0rc1/changelog/20.feature.rst +2 -0
  6. dkist_processing_math-2.2.0rc1/dkist_processing_math/statistics.py +102 -0
  7. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/conftest.py +16 -4
  8. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/test_statistics.py +22 -0
  9. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math.egg-info/PKG-INFO +2 -2
  10. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math.egg-info/SOURCES.txt +3 -1
  11. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math.egg-info/top_level.txt +1 -0
  12. dkist_processing_math-2.1.2/bitbucket-pipelines.yml +0 -100
  13. dkist_processing_math-2.1.2/check_changelog_updated.sh +0 -23
  14. dkist_processing_math-2.1.2/dkist_processing_math/statistics.py +0 -40
  15. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/.gitignore +0 -0
  16. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/.pre-commit-config.yaml +0 -0
  17. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/.readthedocs.yml +0 -0
  18. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/.snyk +0 -0
  19. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/CHANGELOG.rst +0 -0
  20. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/README.rst +0 -0
  21. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/changelog/.gitempty +0 -0
  22. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/__init__.py +0 -0
  23. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/arithmetic.py +0 -0
  24. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/feature.py +0 -0
  25. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/linear_algebra.py +0 -0
  26. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/__init__.py +0 -0
  27. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/test_arithmetic.py +0 -0
  28. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/test_feature.py +0 -0
  29. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/test_linear_algebra.py +0 -0
  30. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/tests/test_transform.py +0 -0
  31. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/transform/__init__.py +0 -0
  32. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/transform/affine.py +0 -0
  33. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/transform/binary.py +0 -0
  34. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/transform/binning.py +0 -0
  35. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math/transform/hough.py +0 -0
  36. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math.egg-info/dependency_links.txt +0 -0
  37. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/dkist_processing_math.egg-info/requires.txt +0 -0
  38. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/Makefile +0 -0
  39. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/changelog.rst +0 -0
  40. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/conf.py +0 -0
  41. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/index.rst +0 -0
  42. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/landing_page.rst +0 -0
  43. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/make.bat +0 -0
  44. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/docs/requirements.txt +0 -0
  45. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/licenses/LICENSE.rst +0 -0
  46. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/pyproject.toml +0 -0
  47. {dkist_processing_math-2.1.2 → dkist_processing_math-2.2.0rc1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dkist-processing-math
3
- Version: 2.1.2
3
+ Version: 2.2.0rc1
4
4
  Summary: Common math functionality used in the DKIST calibrations suite
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -0,0 +1,72 @@
1
+ image: python:3.11
2
+ definitions:
3
+ steps:
4
+ - step: &download_execute_script
5
+ name: Download Script Execute Script
6
+ script:
7
+ - echo "Retrieving Script Execution Script"
8
+ - curl -fL https://getcli.jfrog.io | sh
9
+ - ./jfrog rt dl --url $ARTIFACTORY_URL --user $ARTIFACTORY_USER --password $ARTIFACTORY_PASSWORD generic-packages/ci_scripts/latest/execute_script.sh
10
+ - cat ci_scripts/latest/execute_script.sh
11
+ - chmod 755 ci_scripts/latest/execute_script.sh
12
+ artifacts:
13
+ - ci_scripts/latest/execute_script.sh
14
+ - step: &lint
15
+ caches:
16
+ - pip
17
+ name: Lint
18
+ script:
19
+ - ./ci_scripts/latest/execute_script.sh lint_python.sh
20
+ - step: &changelog
21
+ caches:
22
+ - pip
23
+ name: Changelog
24
+ script:
25
+ - ./ci_scripts/latest/execute_script.sh check_changelog.sh
26
+ - step: &scan
27
+ caches:
28
+ - pip
29
+ name: Scan
30
+ script:
31
+ - ./ci_scripts/latest/execute_script.sh scan_python.sh
32
+ - step: &test
33
+ caches:
34
+ - pip
35
+ name: Test
36
+ script:
37
+ - pip install .[test]
38
+ - pytest --cov -m "not development" dkist_processing_math
39
+ - step: &docs
40
+ name: Build Docs
41
+ caches:
42
+ - pip
43
+ script:
44
+ - ./ci_scripts/latest/execute_script.sh test_sphinx.sh
45
+ - step: &push
46
+ caches:
47
+ - pip
48
+ name: Push
49
+ script:
50
+ - ./ci_scripts/latest/execute_script.sh push_python.sh
51
+
52
+ pipelines:
53
+ default:
54
+ - step: *download_execute_script
55
+ - parallel:
56
+ - step: *lint
57
+ - step: *changelog
58
+ - parallel:
59
+ - step: *scan
60
+ - step: *test
61
+ - step: *docs
62
+ tags:
63
+ 'v*':
64
+ - step: *download_execute_script
65
+ - parallel:
66
+ - step: *changelog
67
+ - step: *lint
68
+ - parallel:
69
+ - step: *scan
70
+ - step: *test
71
+ - step: *docs
72
+ - step: *push
@@ -0,0 +1 @@
1
+ Update bitbucket pipelines to use common scripts for checking for changelog snippets and verifying doc builds.
@@ -0,0 +1 @@
1
+ Update Bitbucket pipelines to use execute script for standard steps.
@@ -0,0 +1,2 @@
1
+ Add `stddev_numpy_arrays` function for computing the per-pixel standard deviation of an iterable of arrays.
2
+ If a `generator` is provided this function is very memory-light, even for huge inputs.
@@ -0,0 +1,102 @@
1
+ """Statistics."""
2
+ from typing import Iterable
3
+ from typing import Union
4
+
5
+ import numpy as np
6
+
7
+
8
+ def average_numpy_arrays(arrays: Union[Iterable[np.ndarray], np.ndarray]) -> np.ndarray:
9
+ """
10
+ Given an iterable of numpy arrays, calculate the pixel-wise average and return it in a numpy array.
11
+
12
+ This will work for a single array as well, just in case...
13
+
14
+ Parameters
15
+ ----------
16
+ arrays
17
+ The arrays to be averaged
18
+
19
+ Returns
20
+ -------
21
+ The average of the input arrays
22
+
23
+ """
24
+ arrays = [arrays] if isinstance(arrays, np.ndarray) else arrays
25
+ count = 0 # This statement is here only to suppress an uninitialized variable warning
26
+ output = None
27
+ for count, array in enumerate(arrays):
28
+ if output is None:
29
+ output = np.array(array).astype(float)
30
+ else:
31
+ if array.shape != output.shape:
32
+ raise ValueError(
33
+ f"All arrays must be the same shape. "
34
+ f"Shape of initial array = {output.shape} "
35
+ f"Shape of current array = {array.shape}"
36
+ )
37
+ output += array
38
+ if output is not None:
39
+ return output / (count + 1)
40
+ raise ValueError("data_arrays is empty")
41
+
42
+
43
+ def stddev_numpy_arrays(arrays: Iterable[np.ndarray]) -> np.ndarray:
44
+ r"""
45
+ Given an iterable of numpy arrays, calculate the pixel-wise standard deviation and return it in a numpy array.
46
+
47
+ This function uses Welford's single-pass algorithm. The standard deviation for the :math:`n^{th}` array is
48
+
49
+ .. math::
50
+ \sigma_n = \sqrt{\frac{M_{2,n}}{n}}
51
+
52
+ where
53
+
54
+ .. math::
55
+ M_{2,n} = M_{2,n-1} + (x_n - \bar{x}_{n-1})(x_n - \bar{x}_n)
56
+
57
+ and
58
+
59
+ .. math::
60
+ \bar{x}_n = \bar{x}_{n-1} + \frac{x_n - \bar{x}_{n-1}}{n}
61
+
62
+ Note that in computing :math:`\sigma` we divide by :math:`n` instead of :math:`(n-1)`. This is to match the default
63
+ behavior of `numpy.std`.
64
+
65
+ Parameters
66
+ ----------
67
+ arrays
68
+ The arrays to be to compute the standard deviation of
69
+
70
+ Returns
71
+ -------
72
+ The standard deviation of the input arrays
73
+ """
74
+ if isinstance(arrays, np.ndarray):
75
+ raise ValueError(
76
+ "Need an Iterator with at least two arrays, but a single array was provided."
77
+ )
78
+
79
+ running_mean = 0.0
80
+ running_M2 = 0.0
81
+ count = 0
82
+ for array in arrays:
83
+ count += 1
84
+ try:
85
+ delta = array - running_mean
86
+ except ValueError:
87
+ raise ValueError(
88
+ f"All arrays must be the same shape. "
89
+ f"Shape of initial array = {running_mean.shape} "
90
+ f"Shape of current array = {array.shape}"
91
+ )
92
+ running_mean += delta / count
93
+ delta2 = array - running_mean
94
+ running_M2 += delta * delta2
95
+
96
+ match count:
97
+ case 0:
98
+ raise ValueError("arrays is empty")
99
+ case 1:
100
+ raise ValueError(f"Need at least two arrays. Provided Iterator only has {count}")
101
+ case _:
102
+ return np.sqrt(running_M2 / count)
@@ -4,8 +4,13 @@ import pytest
4
4
  rng = np.random.default_rng()
5
5
 
6
6
 
7
+ @pytest.fixture
8
+ def test_array_shape() -> tuple[int, int]:
9
+ return (10, 10)
10
+
11
+
7
12
  @pytest.fixture()
8
- def numpy_arrays():
13
+ def numpy_arrays(test_array_shape):
9
14
  """
10
15
  Create an iterable of random 10 x 10 arrays
11
16
 
@@ -14,7 +19,11 @@ def numpy_arrays():
14
19
  List[np.ndarray]
15
20
 
16
21
  """
17
- arrays = [rng.standard_normal((10, 10)), rng.standard_normal((10, 10))]
22
+ arrays = [
23
+ rng.standard_normal(test_array_shape),
24
+ rng.standard_normal(test_array_shape),
25
+ rng.standard_normal(test_array_shape),
26
+ ]
18
27
  return arrays
19
28
 
20
29
 
@@ -32,7 +41,7 @@ def numpy_array(numpy_arrays):
32
41
 
33
42
 
34
43
  @pytest.fixture()
35
- def numpy_arrays_wrong_shape():
44
+ def numpy_arrays_wrong_shape(test_array_shape):
36
45
  """
37
46
  Create an iterable of random arrays of differing sizes
38
47
 
@@ -41,7 +50,10 @@ def numpy_arrays_wrong_shape():
41
50
  List[np.ndarray]
42
51
 
43
52
  """
44
- arrays = [rng.standard_normal((10, 10)), rng.standard_normal((10, 15))]
53
+ arrays = [
54
+ rng.standard_normal(test_array_shape),
55
+ rng.standard_normal(tuple(i * 2 for i in test_array_shape)),
56
+ ]
45
57
  return arrays
46
58
 
47
59
 
@@ -2,6 +2,7 @@ import numpy as np
2
2
  import pytest
3
3
 
4
4
  from dkist_processing_math.statistics import average_numpy_arrays
5
+ from dkist_processing_math.statistics import stddev_numpy_arrays
5
6
 
6
7
 
7
8
  @pytest.fixture()
@@ -60,3 +61,24 @@ def test_average_with_large_values(int_arrays_with_large_values):
60
61
  """
61
62
  expected = np.ones((10, 10)) * 17500
62
63
  np.testing.assert_equal(expected, average_numpy_arrays(int_arrays_with_large_values))
64
+
65
+
66
+ def test_stddev_numpy_arrays(numpy_arrays):
67
+ expected_result = np.std(numpy_arrays, axis=0)
68
+ result = stddev_numpy_arrays(numpy_arrays)
69
+
70
+ np.testing.assert_allclose(result, expected_result)
71
+
72
+
73
+ def test_stddec_numpy_arrays_failures(numpy_arrays, numpy_arrays_wrong_shape):
74
+ with pytest.raises(ValueError, match="Need an Iterator with at least two arrays"):
75
+ stddev_numpy_arrays(numpy_arrays[0])
76
+
77
+ with pytest.raises(ValueError, match="All arrays must be the same shape"):
78
+ stddev_numpy_arrays(numpy_arrays_wrong_shape)
79
+
80
+ with pytest.raises(ValueError, match="Need at least two arrays"):
81
+ stddev_numpy_arrays([numpy_arrays[0]])
82
+
83
+ with pytest.raises(ValueError, match="arrays is empty"):
84
+ stddev_numpy_arrays([])
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: dkist-processing-math
3
- Version: 2.1.2
3
+ Version: 2.2.0rc1
4
4
  Summary: Common math functionality used in the DKIST calibrations suite
5
5
  Author-email: NSO / AURA <dkistdc@nso.edu>
6
6
  License: BSD-3-Clause
@@ -5,9 +5,11 @@
5
5
  CHANGELOG.rst
6
6
  README.rst
7
7
  bitbucket-pipelines.yml
8
- check_changelog_updated.sh
9
8
  pyproject.toml
10
9
  changelog/.gitempty
10
+ changelog/18.misc.rst
11
+ changelog/19.misc.rst
12
+ changelog/20.feature.rst
11
13
  dkist_processing_math/__init__.py
12
14
  dkist_processing_math/arithmetic.py
13
15
  dkist_processing_math/feature.py
@@ -1,4 +1,5 @@
1
1
  changelog
2
+ ci_scripts
2
3
  dkist_processing_math
3
4
  docs
4
5
  licenses
@@ -1,100 +0,0 @@
1
- image: python:3.11
2
- definitions:
3
- steps:
4
- - step: &lint
5
- caches:
6
- - pip
7
- name: Lint
8
- script:
9
- - echo "Retrieving and Executing Lint Script"
10
- - curl -fL https://getcli.jfrog.io | sh
11
- - ./jfrog rt dl --url $ARTIFACTORY_URL --user $ARTIFACTORY_USER --password $ARTIFACTORY_PASSWORD generic-packages/ci_scripts/latest/lint_python.sh
12
- - cat ci_scripts/latest/lint_python.sh
13
- - chmod 755 ci_scripts/latest/lint_python.sh
14
- - ./ci_scripts/latest/lint_python.sh
15
- - step: &changelog
16
- caches:
17
- - pip
18
- name: Changelog
19
- script:
20
- - pip install towncrier
21
- # We need to fetch the main branch to compare against
22
- - git remote set-branches --add origin main
23
- - git fetch origin main
24
- - towncrier check --compare-with origin/main
25
- - step: &scan
26
- caches:
27
- - pip
28
- name: Scan
29
- script:
30
- - echo "Retrieving and Executing Scan Script"
31
- - curl -fL https://getcli.jfrog.io | sh
32
- - ./jfrog rt dl --url $ARTIFACTORY_URL --user $ARTIFACTORY_USER --password $ARTIFACTORY_PASSWORD generic-packages/ci_scripts/latest/scan_python.sh
33
- - cat ci_scripts/latest/scan_python.sh
34
- - chmod 755 ci_scripts/latest/scan_python.sh
35
- - ./ci_scripts/latest/scan_python.sh
36
- - step: &test
37
- caches:
38
- - pip
39
- name: Test
40
- script:
41
- - pip install .[test]
42
- - pytest --cov -m "not development" dkist_processing_math
43
- - step: &docs
44
- name: Build Docs
45
- caches:
46
- - pip
47
- script:
48
- - apt update && apt -y install graphviz
49
- - pip install .[docs]
50
- - sphinx-build --color -W --keep-going -b html docs docs/_build/html
51
- - step: &check_changelog
52
- name: Check for updated CHANGELOG
53
- script:
54
- - ./check_changelog_updated.sh
55
- - step: &push
56
- caches:
57
- - pip
58
- name: Push
59
- script:
60
- - pip install -U pip
61
- - pip install build twine
62
- - python -m build --outdir wheelhouse .
63
- - python -m twine upload --skip-existing wheelhouse/*
64
-
65
- pipelines:
66
- default:
67
- - parallel:
68
- - step: *lint
69
- - step: *changelog
70
- - parallel:
71
- - step: *scan
72
- - step: *test
73
- - step: *docs
74
- custom:
75
- skip_doc_test_to_build_rc: # I.e. skip the doc check (because we might have rc dependencies)
76
- - variables:
77
- - name: BITBUCKET_TAG
78
- description: "Tag version to build (e.g., 'vX.Y.ZrcR')"
79
- - step:
80
- name: Validate Bitbucket pipeline input
81
- script:
82
- - git tag | grep -q ${BITBUCKET_TAG} || { echo Tag ${BITBUCKET_TAG} not found!; exit 1; }
83
- - echo ${BITBUCKET_TAG} | grep -q "rc[0-9]\+$" || { echo Tag ${BITBUCKET_TAG} is not an rc. SHAME!; exit 1; }
84
- - parallel:
85
- - step: *lint
86
- - step: *changelog
87
- - parallel:
88
- - step: *scan
89
- - step: *test
90
- - step: *push
91
- tags:
92
- 'v*':
93
- - parallel:
94
- - step: *check_changelog
95
- - step: *lint
96
- - parallel:
97
- - step: *scan
98
- - step: *test
99
- - step: *docs
100
- - step: *push
@@ -1,23 +0,0 @@
1
- #!/bin/bash
2
-
3
- CURRENT_VERSION=`git describe --tags --match v* --exact-match`
4
- ERROR_STR="CHANGELOG has not been updated for ${CURRENT_VERSION}\\nSee the README for instructions"
5
- ERROR_PAD="***********"
6
-
7
- if [[ $CURRENT_VERSION =~ "rc" ]]; then
8
- echo "release candidate detected"
9
- exit 0;
10
- fi
11
-
12
- ls changelog/*rst 2>/dev/null && {
13
- echo -e "\\n${ERROR_PAD}"
14
- echo -e "Unmerged changelog fragments found! You must run towncrier!\\nSee the README for instruction"
15
- echo -e "${ERROR_PAD}"
16
- exit 1;
17
- }
18
-
19
- head -n 1 CHANGELOG.rst | grep -q "^$CURRENT_VERSION (" - || {
20
- echo -e "\\n${ERROR_PAD}"
21
- echo -e $ERROR_STR;
22
- echo -e "${ERROR_PAD}"
23
- exit 1; }
@@ -1,40 +0,0 @@
1
- """Statistics."""
2
- from typing import Iterable
3
- from typing import Union
4
-
5
- import numpy as np
6
-
7
-
8
- def average_numpy_arrays(arrays: Union[Iterable[np.ndarray], np.ndarray]) -> np.ndarray:
9
- """
10
- Given an iterable of numpy arrays, calculate the pixel-wise average and return it in a numpy array.
11
-
12
- This will work for a single array as well, just in case...
13
-
14
- Parameters
15
- ----------
16
- arrays
17
- The arrays to be averaged
18
-
19
- Returns
20
- -------
21
- The average of the input arrays
22
-
23
- """
24
- arrays = [arrays] if isinstance(arrays, np.ndarray) else arrays
25
- count = 0 # This statement is here only to suppress an uninitialized variable warning
26
- output = None
27
- for count, array in enumerate(arrays):
28
- if output is None:
29
- output = np.array(array).astype(float)
30
- else:
31
- if array.shape != output.shape:
32
- raise ValueError(
33
- f"All arrays must be the same shape. "
34
- f"Shape of initial array = {output.shape} "
35
- f"Shape of current array = {array.shape}"
36
- )
37
- output += array
38
- if output is not None:
39
- return output / (count + 1)
40
- raise ValueError("data_arrays is empty")