nrl-tracker 1.11.1__tar.gz → 1.12.1__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 (270) hide show
  1. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/CONTRIBUTING.md +7 -7
  2. {nrl_tracker-1.11.1/nrl_tracker.egg-info → nrl_tracker-1.12.1}/PKG-INFO +5 -4
  3. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/README.md +4 -3
  4. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1/nrl_tracker.egg-info}/PKG-INFO +5 -4
  5. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/nrl_tracker.egg-info/SOURCES.txt +12 -0
  6. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pyproject.toml +1 -1
  7. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/__init__.py +2 -2
  8. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/network_flow.py +172 -60
  9. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/time_systems.py +21 -0
  10. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/cluster_set.py +36 -0
  11. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/conversions/geodetic.py +58 -0
  12. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/array_utils.py +52 -0
  13. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/ekf.py +46 -0
  14. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/kalman.py +16 -0
  15. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/matrix_utils.py +44 -1
  16. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/particle_filter.py +33 -0
  17. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/ukf.py +31 -0
  18. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/utils.py +15 -0
  19. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/magnetism/igrf.py +72 -0
  20. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/magnetism/wmm.py +52 -0
  21. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/basic_matrix/decompositions.py +7 -0
  22. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/basic_matrix/special_matrices.py +31 -0
  23. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/geometry/geometry.py +33 -0
  24. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/interpolation/interpolation.py +83 -0
  25. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/signal_processing/detection.py +31 -0
  26. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/signal_processing/filters.py +56 -0
  27. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/signal_processing/matched_filter.py +32 -1
  28. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/hypergeometric.py +17 -0
  29. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/statistics/estimators.py +71 -0
  30. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/transforms/wavelets.py +25 -0
  31. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/great_circle.py +33 -0
  32. nrl_tracker-1.12.1/tests/test_debye_comprehensive.py +394 -0
  33. nrl_tracker-1.12.1/tests/test_detection_comprehensive.py +394 -0
  34. nrl_tracker-1.12.1/tests/test_distributions_comprehensive.py +371 -0
  35. nrl_tracker-1.12.1/tests/test_egm_comprehensive.py +354 -0
  36. nrl_tracker-1.12.1/tests/test_gpu_utils_comprehensive.py +386 -0
  37. nrl_tracker-1.12.1/tests/test_hypergeometric_comprehensive.py +287 -0
  38. nrl_tracker-1.12.1/tests/test_hypergeometric_stft_targeted.py +322 -0
  39. nrl_tracker-1.12.1/tests/test_lambert_comprehensive.py +428 -0
  40. nrl_tracker-1.12.1/tests/test_maturity_comprehensive.py +310 -0
  41. nrl_tracker-1.12.1/tests/test_metrics_plotting_comprehensive.py +470 -0
  42. nrl_tracker-1.12.1/tests/test_network_flow_comprehensive.py +381 -0
  43. nrl_tracker-1.12.1/tests/test_stft_comprehensive.py +369 -0
  44. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/LICENSE +0 -0
  45. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/MANIFEST.in +0 -0
  46. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/nrl_tracker.egg-info/dependency_links.txt +0 -0
  47. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/nrl_tracker.egg-info/requires.txt +0 -0
  48. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/nrl_tracker.egg-info/top_level.txt +0 -0
  49. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/__init__.py +0 -0
  50. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/data_association.py +0 -0
  51. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/dijkstra_min_cost.py +0 -0
  52. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/gating.py +0 -0
  53. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/jpda.py +0 -0
  54. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/nd_assignment.py +0 -0
  55. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/network_simplex.py +0 -0
  56. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/three_dimensional/__init__.py +0 -0
  57. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/three_dimensional/assignment.py +0 -0
  58. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/two_dimensional/__init__.py +0 -0
  59. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/two_dimensional/assignment.py +0 -0
  60. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/assignment_algorithms/two_dimensional/kbest.py +0 -0
  61. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/__init__.py +0 -0
  62. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/ephemerides.py +0 -0
  63. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/lambert.py +0 -0
  64. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/orbital_mechanics.py +0 -0
  65. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/reference_frames.py +0 -0
  66. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/relativity.py +0 -0
  67. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/sgp4.py +0 -0
  68. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/special_orbits.py +0 -0
  69. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/astronomical/tle.py +0 -0
  70. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/atmosphere/__init__.py +0 -0
  71. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/atmosphere/ionosphere.py +0 -0
  72. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/atmosphere/models.py +0 -0
  73. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/atmosphere/nrlmsise00.py +0 -0
  74. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/clustering/__init__.py +0 -0
  75. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/clustering/dbscan.py +0 -0
  76. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/clustering/gaussian_mixture.py +0 -0
  77. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/clustering/hierarchical.py +0 -0
  78. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/clustering/kmeans.py +0 -0
  79. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/__init__.py +0 -0
  80. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/base.py +0 -0
  81. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/covertree.py +0 -0
  82. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/kd_tree.py +0 -0
  83. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/measurement_set.py +0 -0
  84. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/rtree.py +0 -0
  85. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/track_list.py +0 -0
  86. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/containers/vptree.py +0 -0
  87. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/__init__.py +0 -0
  88. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/conversions/__init__.py +0 -0
  89. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/conversions/spherical.py +0 -0
  90. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/jacobians/__init__.py +0 -0
  91. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/jacobians/jacobians.py +0 -0
  92. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/projections/__init__.py +0 -0
  93. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/projections/projections.py +0 -0
  94. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/rotations/__init__.py +0 -0
  95. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/coordinate_systems/rotations/rotations.py +0 -0
  96. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/__init__.py +0 -0
  97. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/constants.py +0 -0
  98. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/exceptions.py +0 -0
  99. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/maturity.py +0 -0
  100. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/optional_deps.py +0 -0
  101. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/core/validation.py +0 -0
  102. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/__init__.py +0 -0
  103. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/batch_estimation/__init__.py +0 -0
  104. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/gaussian_sum_filter.py +0 -0
  105. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/imm.py +0 -0
  106. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/information_filter.py +0 -0
  107. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/__init__.py +0 -0
  108. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/constrained.py +0 -0
  109. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/extended.py +0 -0
  110. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/h_infinity.py +0 -0
  111. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/linear.py +0 -0
  112. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/matrix_utils.py +0 -0
  113. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/square_root.py +0 -0
  114. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/sr_ukf.py +0 -0
  115. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/types.py +0 -0
  116. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/ud_filter.py +0 -0
  117. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/kalman/unscented.py +0 -0
  118. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/measurement_update/__init__.py +0 -0
  119. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/particle_filters/__init__.py +0 -0
  120. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/particle_filters/bootstrap.py +0 -0
  121. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/rbpf.py +0 -0
  122. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_estimation/smoothers.py +0 -0
  123. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/__init__.py +0 -0
  124. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/continuous_time/__init__.py +0 -0
  125. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/continuous_time/dynamics.py +0 -0
  126. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/discrete_time/__init__.py +0 -0
  127. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/discrete_time/coordinated_turn.py +0 -0
  128. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/discrete_time/polynomial.py +0 -0
  129. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/discrete_time/singer.py +0 -0
  130. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/process_noise/__init__.py +0 -0
  131. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/process_noise/coordinated_turn.py +0 -0
  132. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/process_noise/polynomial.py +0 -0
  133. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/dynamic_models/process_noise/singer.py +0 -0
  134. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gpu/__init__.py +0 -0
  135. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/__init__.py +0 -0
  136. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/clenshaw.py +0 -0
  137. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/egm.py +0 -0
  138. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/models.py +0 -0
  139. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/spherical_harmonics.py +0 -0
  140. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/gravity/tides.py +0 -0
  141. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/logging_config.py +0 -0
  142. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/magnetism/__init__.py +0 -0
  143. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/magnetism/emm.py +0 -0
  144. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/__init__.py +0 -0
  145. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/basic_matrix/__init__.py +0 -0
  146. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/combinatorics/__init__.py +0 -0
  147. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/combinatorics/combinatorics.py +0 -0
  148. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/continuous_optimization/__init__.py +0 -0
  149. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/geometry/__init__.py +0 -0
  150. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/interpolation/__init__.py +0 -0
  151. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/numerical_integration/__init__.py +0 -0
  152. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/numerical_integration/quadrature.py +0 -0
  153. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/polynomials/__init__.py +0 -0
  154. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/signal_processing/__init__.py +0 -0
  155. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/__init__.py +0 -0
  156. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/bessel.py +0 -0
  157. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/debye.py +0 -0
  158. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/elliptic.py +0 -0
  159. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/error_functions.py +0 -0
  160. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/gamma_functions.py +0 -0
  161. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/lambert_w.py +0 -0
  162. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/special_functions/marcum_q.py +0 -0
  163. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/statistics/__init__.py +0 -0
  164. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/statistics/distributions.py +0 -0
  165. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/transforms/__init__.py +0 -0
  166. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/transforms/fourier.py +0 -0
  167. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/mathematical_functions/transforms/stft.py +0 -0
  168. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/misc/__init__.py +0 -0
  169. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/__init__.py +0 -0
  170. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/geodesy.py +0 -0
  171. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/ins.py +0 -0
  172. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/ins_gnss.py +0 -0
  173. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/navigation/rhumb.py +0 -0
  174. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/performance_evaluation/__init__.py +0 -0
  175. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/performance_evaluation/estimation_metrics.py +0 -0
  176. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/performance_evaluation/track_metrics.py +0 -0
  177. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/physical_values/__init__.py +0 -0
  178. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/plotting/__init__.py +0 -0
  179. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/plotting/coordinates.py +0 -0
  180. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/plotting/ellipses.py +0 -0
  181. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/plotting/metrics.py +0 -0
  182. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/plotting/tracks.py +0 -0
  183. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/scheduling/__init__.py +0 -0
  184. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/static_estimation/__init__.py +0 -0
  185. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/static_estimation/least_squares.py +0 -0
  186. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/static_estimation/maximum_likelihood.py +0 -0
  187. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/static_estimation/robust.py +0 -0
  188. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/terrain/__init__.py +0 -0
  189. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/terrain/dem.py +0 -0
  190. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/terrain/loaders.py +0 -0
  191. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/terrain/visibility.py +0 -0
  192. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/trackers/__init__.py +0 -0
  193. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/trackers/hypothesis.py +0 -0
  194. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/trackers/mht.py +0 -0
  195. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/trackers/multi_target.py +0 -0
  196. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/trackers/single_target.py +0 -0
  197. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/pytcl/transponders/__init__.py +0 -0
  198. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/setup.cfg +0 -0
  199. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/__init__.py +0 -0
  200. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/conftest.py +0 -0
  201. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_additional_trees.py +0 -0
  202. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_assignment_algorithms.py +0 -0
  203. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_astronomical.py +0 -0
  204. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_cfar_detection.py +0 -0
  205. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_clustering.py +0 -0
  206. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_combinatorics.py +0 -0
  207. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_constrained_ekf.py +0 -0
  208. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_coordinate_systems.py +0 -0
  209. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_coverage_boost.py +0 -0
  210. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_coverage_boost_2.py +0 -0
  211. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_debye.py +0 -0
  212. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_dynamic_models.py +0 -0
  213. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_egm.py +0 -0
  214. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_elliptic.py +0 -0
  215. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_emm.py +0 -0
  216. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_ephemerides.py +0 -0
  217. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_error_functions.py +0 -0
  218. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_exceptions.py +0 -0
  219. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_gamma_functions.py +0 -0
  220. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_gaussian_mixtures.py +0 -0
  221. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_gaussian_sum_filter.py +0 -0
  222. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_geometry.py +0 -0
  223. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_geophysical.py +0 -0
  224. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_gpu.py +0 -0
  225. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_gpu_utils.py +0 -0
  226. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_great_circle.py +0 -0
  227. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_h_infinity.py +0 -0
  228. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_hypergeometric.py +0 -0
  229. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_ins.py +0 -0
  230. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_ins_gnss.py +0 -0
  231. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_ionosphere.py +0 -0
  232. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_jpda.py +0 -0
  233. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_kalman_filters.py +0 -0
  234. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_marcum_q.py +0 -0
  235. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_matched_filter.py +0 -0
  236. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_mathematical_functions.py +0 -0
  237. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_maximum_likelihood.py +0 -0
  238. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_mht.py +0 -0
  239. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_nd_assignment.py +0 -0
  240. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_network_flow.py +0 -0
  241. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_nrlmsise00.py +0 -0
  242. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_optional_deps.py +0 -0
  243. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_performance_evaluation.py +0 -0
  244. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_phase6_specialized.py +0 -0
  245. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_plotting.py +0 -0
  246. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_projections.py +0 -0
  247. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_quadrature.py +0 -0
  248. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_rbpf.py +0 -0
  249. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_relativity.py +0 -0
  250. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_rhumb.py +0 -0
  251. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_rotations.py +0 -0
  252. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_sgp4.py +0 -0
  253. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_signal_processing.py +0 -0
  254. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_smoothers.py +0 -0
  255. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_spatial_containers_parametrized.py +0 -0
  256. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_spatial_structures.py +0 -0
  257. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_special_functions.py +0 -0
  258. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_special_orbits.py +0 -0
  259. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_square_root_filters.py +0 -0
  260. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_static_estimation.py +0 -0
  261. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_terrain.py +0 -0
  262. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_terrain_loaders.py +0 -0
  263. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_tides.py +0 -0
  264. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_tod_mod.py +0 -0
  265. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_trackers.py +0 -0
  266. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_tracking_containers.py +0 -0
  267. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_transforms.py +0 -0
  268. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_validation.py +0 -0
  269. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/test_wavelets.py +0 -0
  270. {nrl_tracker-1.11.1 → nrl_tracker-1.12.1}/tests/unit/test_core.py +0 -0
@@ -148,8 +148,8 @@ from scipy.io import loadmat
148
148
  import numpy as np
149
149
 
150
150
  data = loadmat('cart2sphere_reference.mat')
151
- np.savez('cart2sphere_reference.npz',
152
- input=data['input'],
151
+ np.savez('cart2sphere_reference.npz',
152
+ input=data['input'],
153
153
  expected=data['output'])
154
154
  ```
155
155
 
@@ -176,10 +176,10 @@ When porting a function from the original MATLAB library:
176
176
  Notes
177
177
  -----
178
178
  This is a port of Cart2Sphere.m from the MATLAB Tracker Component Library.
179
-
179
+
180
180
  References
181
181
  ----------
182
- .. [1] Original implementation:
182
+ .. [1] Original implementation:
183
183
  https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary
184
184
  ```
185
185
 
@@ -204,13 +204,13 @@ When porting a function from the original MATLAB library:
204
204
  ```bash
205
205
  # Format code
206
206
  black .
207
-
207
+
208
208
  # Lint
209
209
  flake8 pytcl tests
210
-
210
+
211
211
  # Type check
212
212
  mypy pytcl
213
-
213
+
214
214
  # Run tests
215
215
  pytest
216
216
  ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.11.1
3
+ Version: 1.12.1
4
4
  Summary: Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms
5
5
  Author: Original: David F. Crouse, Naval Research Laboratory
6
6
  Maintainer: Python Port Contributors
@@ -71,17 +71,18 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
71
71
 
72
72
  # Tracker Component Library (Python)
73
73
 
74
- [![PyPI version](https://img.shields.io/badge/pypi-v1.11.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
74
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.12.1-blue.svg)](https://pypi.org/project/nrl-tracker/)
75
75
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
76
76
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
77
77
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
78
- [![Tests](https://img.shields.io/badge/tests-2894%20passing-success.svg)](https://github.com/nedonatelli/TCL)
78
+ [![Tests](https://img.shields.io/badge/tests-3280%20passing-success.svg)](https://github.com/nedonatelli/TCL)
79
79
  [![MATLAB Parity](https://img.shields.io/badge/MATLAB%20Parity-100%25-brightgreen.svg)](docs/gap_analysis.rst)
80
+ [![Coverage](https://img.shields.io/badge/coverage-80%25-brightgreen.svg)](htmlcov/index.html)
80
81
  [![Type Checking](https://img.shields.io/badge/mypy--strict-passing-brightgreen.svg)](mypy.ini)
81
82
 
82
83
  A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
83
84
 
84
- **1,070+ functions** | **153 modules** | **2,894 tests** | **100% MATLAB parity**
85
+ **1,070+ functions** | **153 modules** | **3,280 tests** | **100% MATLAB parity**
85
86
 
86
87
  ## Overview
87
88
 
@@ -1,16 +1,17 @@
1
1
  # Tracker Component Library (Python)
2
2
 
3
- [![PyPI version](https://img.shields.io/badge/pypi-v1.11.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
3
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.12.1-blue.svg)](https://pypi.org/project/nrl-tracker/)
4
4
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
5
5
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
6
6
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
7
- [![Tests](https://img.shields.io/badge/tests-2894%20passing-success.svg)](https://github.com/nedonatelli/TCL)
7
+ [![Tests](https://img.shields.io/badge/tests-3280%20passing-success.svg)](https://github.com/nedonatelli/TCL)
8
8
  [![MATLAB Parity](https://img.shields.io/badge/MATLAB%20Parity-100%25-brightgreen.svg)](docs/gap_analysis.rst)
9
+ [![Coverage](https://img.shields.io/badge/coverage-80%25-brightgreen.svg)](htmlcov/index.html)
9
10
  [![Type Checking](https://img.shields.io/badge/mypy--strict-passing-brightgreen.svg)](mypy.ini)
10
11
 
11
12
  A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
12
13
 
13
- **1,070+ functions** | **153 modules** | **2,894 tests** | **100% MATLAB parity**
14
+ **1,070+ functions** | **153 modules** | **3,280 tests** | **100% MATLAB parity**
14
15
 
15
16
  ## Overview
16
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.11.1
3
+ Version: 1.12.1
4
4
  Summary: Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms
5
5
  Author: Original: David F. Crouse, Naval Research Laboratory
6
6
  Maintainer: Python Port Contributors
@@ -71,17 +71,18 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
71
71
 
72
72
  # Tracker Component Library (Python)
73
73
 
74
- [![PyPI version](https://img.shields.io/badge/pypi-v1.11.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
74
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.12.1-blue.svg)](https://pypi.org/project/nrl-tracker/)
75
75
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
76
76
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
77
77
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
78
- [![Tests](https://img.shields.io/badge/tests-2894%20passing-success.svg)](https://github.com/nedonatelli/TCL)
78
+ [![Tests](https://img.shields.io/badge/tests-3280%20passing-success.svg)](https://github.com/nedonatelli/TCL)
79
79
  [![MATLAB Parity](https://img.shields.io/badge/MATLAB%20Parity-100%25-brightgreen.svg)](docs/gap_analysis.rst)
80
+ [![Coverage](https://img.shields.io/badge/coverage-80%25-brightgreen.svg)](htmlcov/index.html)
80
81
  [![Type Checking](https://img.shields.io/badge/mypy--strict-passing-brightgreen.svg)](mypy.ini)
81
82
 
82
83
  A Python port of the [U.S. Naval Research Laboratory's Tracker Component Library](https://github.com/USNavalResearchLaboratory/TrackerComponentLibrary), a comprehensive collection of algorithms for target tracking, estimation, coordinate systems, and related mathematical functions.
83
84
 
84
- **1,070+ functions** | **153 modules** | **2,894 tests** | **100% MATLAB parity**
85
+ **1,070+ functions** | **153 modules** | **3,280 tests** | **100% MATLAB parity**
85
86
 
86
87
  ## Overview
87
88
 
@@ -195,8 +195,12 @@ tests/test_coordinate_systems.py
195
195
  tests/test_coverage_boost.py
196
196
  tests/test_coverage_boost_2.py
197
197
  tests/test_debye.py
198
+ tests/test_debye_comprehensive.py
199
+ tests/test_detection_comprehensive.py
200
+ tests/test_distributions_comprehensive.py
198
201
  tests/test_dynamic_models.py
199
202
  tests/test_egm.py
203
+ tests/test_egm_comprehensive.py
200
204
  tests/test_elliptic.py
201
205
  tests/test_emm.py
202
206
  tests/test_ephemerides.py
@@ -209,21 +213,28 @@ tests/test_geometry.py
209
213
  tests/test_geophysical.py
210
214
  tests/test_gpu.py
211
215
  tests/test_gpu_utils.py
216
+ tests/test_gpu_utils_comprehensive.py
212
217
  tests/test_great_circle.py
213
218
  tests/test_h_infinity.py
214
219
  tests/test_hypergeometric.py
220
+ tests/test_hypergeometric_comprehensive.py
221
+ tests/test_hypergeometric_stft_targeted.py
215
222
  tests/test_ins.py
216
223
  tests/test_ins_gnss.py
217
224
  tests/test_ionosphere.py
218
225
  tests/test_jpda.py
219
226
  tests/test_kalman_filters.py
227
+ tests/test_lambert_comprehensive.py
220
228
  tests/test_marcum_q.py
221
229
  tests/test_matched_filter.py
222
230
  tests/test_mathematical_functions.py
231
+ tests/test_maturity_comprehensive.py
223
232
  tests/test_maximum_likelihood.py
233
+ tests/test_metrics_plotting_comprehensive.py
224
234
  tests/test_mht.py
225
235
  tests/test_nd_assignment.py
226
236
  tests/test_network_flow.py
237
+ tests/test_network_flow_comprehensive.py
227
238
  tests/test_nrlmsise00.py
228
239
  tests/test_optional_deps.py
229
240
  tests/test_performance_evaluation.py
@@ -244,6 +255,7 @@ tests/test_special_functions.py
244
255
  tests/test_special_orbits.py
245
256
  tests/test_square_root_filters.py
246
257
  tests/test_static_estimation.py
258
+ tests/test_stft_comprehensive.py
247
259
  tests/test_terrain.py
248
260
  tests/test_terrain_loaders.py
249
261
  tests/test_tides.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nrl-tracker"
7
- version = "1.11.1"
7
+ version = "1.12.1"
8
8
  description = "Python port of the U.S. Naval Research Laboratory's Tracker Component Library for target tracking algorithms"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -6,7 +6,7 @@ systems, dynamic models, estimation algorithms, and mathematical functions.
6
6
 
7
7
  This is a Python port of the U.S. Naval Research Laboratory's Tracker Component
8
8
  Library originally written in MATLAB.
9
- **Current Version:** 1.11.1 (January 5, 2026)
9
+ **Current Version:** 1.12.1 (January 5, 2026)
10
10
  **Status:** Production-ready, 2,894 tests passing, 76% line coverage
11
11
  Examples
12
12
  --------
@@ -21,7 +21,7 @@ References
21
21
  no. 5, pp. 18-27, May 2017.
22
22
  """
23
23
 
24
- __version__ = "1.11.1"
24
+ __version__ = "1.12.1"
25
25
  __author__ = "Python Port Contributors"
26
26
  __original_author__ = "David F. Crouse, Naval Research Laboratory"
27
27
 
@@ -179,13 +179,19 @@ def min_cost_flow_successive_shortest_paths(
179
179
  max_iterations: int = 1000,
180
180
  ) -> MinCostFlowResult:
181
181
  """
182
- Solve min-cost flow using successive shortest paths.
182
+ Solve min-cost flow using successive shortest paths with cost scaling.
183
183
 
184
184
  Algorithm:
185
- 1. While there is excess supply:
186
- - Find shortest path from a supply node to a demand node
187
- - Push maximum feasible flow along path
188
- - Update supplies and residual capacities
185
+ 1. Initialize potentials using Bellman-Ford
186
+ 2. While there is excess supply:
187
+ - Find shortest path using reduced costs (Dijkstra with potentials)
188
+ - Push unit flow along path
189
+ - Update node potentials
190
+ - Recompute shortest paths to maintain optimality
191
+
192
+ This is the standard min-cost flow algorithm that guarantees optimality
193
+ and convergence. It uses Dijkstra's algorithm with potentials, which
194
+ maintains the dual feasibility (reduced cost property).
189
195
 
190
196
  Parameters
191
197
  ----------
@@ -217,100 +223,163 @@ def min_cost_flow_successive_shortest_paths(
217
223
 
218
224
  Notes
219
225
  -----
220
- This is a simplified implementation using Bellman-Ford for shortest
221
- paths. Production code would use more efficient implementations.
226
+ This implementation uses successive shortest paths with potentials.
227
+ The algorithm is guaranteed to find the optimal solution for any
228
+ feasible min-cost flow problem.
229
+
230
+ For rectangular assignment problems (m < n or m > n), all m units
231
+ of flow must be satisfied. The algorithm ensures this by finding
232
+ augmenting paths until all supply is routed.
222
233
  """
223
234
  n_nodes = len(supplies)
224
235
  n_edges = len(edges)
225
236
 
226
- # Build adjacency lists for residual graph
227
- graph: list[list[tuple[int, int, float]]] = [[] for _ in range(n_nodes)]
237
+ # Initialize flow and residual capacity
228
238
  flow = np.zeros(n_edges)
229
239
  residual_capacity = np.array([e.capacity for e in edges])
230
240
 
241
+ # Initialize node potentials using Bellman-Ford from a dummy source
242
+ # This ensures all potentials are finite and maintains dual feasibility
243
+ potential = np.zeros(n_nodes)
244
+
245
+ # Build adjacency list representation
246
+ # Each entry: (to_node, edge_idx, is_reverse, cost)
247
+ graph: list[list[tuple[int, int, int, float]]] = [[] for _ in range(n_nodes)]
248
+
231
249
  for edge_idx, edge in enumerate(edges):
232
- graph[edge.from_node].append((edge.to_node, edge_idx, edge.cost))
233
- # Add reverse edge with negative cost
234
- graph[edge.to_node].append((edge.from_node, edge_idx, -edge.cost))
250
+ # Forward edge
251
+ graph[edge.from_node].append((edge.to_node, edge_idx, 0, edge.cost))
252
+ # Reverse edge (for flow cancellation)
253
+ graph[edge.to_node].append((edge.from_node, edge_idx, 1, -edge.cost))
235
254
 
236
255
  current_supplies = supplies.copy()
237
256
  iteration = 0
238
257
 
258
+ # Main algorithm loop
239
259
  while iteration < max_iterations:
240
- # Find a node with excess supply
241
- excess_node = None
260
+ # Find excess and deficit nodes
261
+ excess_node = -1
262
+ deficit_node = -1
263
+
242
264
  for node in range(n_nodes):
243
265
  if current_supplies[node] > 1e-10:
244
266
  excess_node = node
245
267
  break
246
268
 
247
- if excess_node is None:
248
- break
269
+ if excess_node < 0:
270
+ break # No more excess nodes
249
271
 
250
- # Find a node with deficit
251
- deficit_node = None
252
272
  for node in range(n_nodes):
253
273
  if current_supplies[node] < -1e-10:
254
274
  deficit_node = node
255
275
  break
256
276
 
257
- if deficit_node is None:
258
- break
277
+ if deficit_node < 0:
278
+ break # No deficit nodes
259
279
 
260
- # Find shortest path using Bellman-Ford relaxation
280
+ # Find shortest path using Dijkstra with potentials
281
+ # Reduced cost: c_reduced(u,v) = c(u,v) + π(u) - π(v)
261
282
  dist = np.full(n_nodes, np.inf)
262
283
  dist[excess_node] = 0.0
263
284
  parent = np.full(n_nodes, -1, dtype=int)
264
285
  parent_edge = np.full(n_nodes, -1, dtype=int)
286
+ parent_reverse = np.full(n_nodes, 0, dtype=int)
287
+ visited = np.zeros(n_nodes, dtype=bool)
288
+
289
+ # Dijkstra's algorithm
290
+ for _ in range(n_nodes):
291
+ # Find unvisited node with minimum distance
292
+ u = -1
293
+ min_dist = np.inf
294
+ for node in range(n_nodes):
295
+ if not visited[node] and dist[node] < min_dist:
296
+ u = node
297
+ min_dist = dist[node]
298
+
299
+ if u < 0 or dist[u] == np.inf:
300
+ break
301
+
302
+ visited[u] = True
265
303
 
266
- for _ in range(n_nodes - 1):
267
- for u in range(n_nodes):
268
- if dist[u] == np.inf:
269
- continue
270
- for v, edge_idx, cost in graph[u]:
271
- if residual_capacity[edge_idx] > 1e-10:
272
- new_dist = dist[u] + cost
273
- if new_dist < dist[v]:
274
- dist[v] = new_dist
275
- parent[v] = u
276
- parent_edge[v] = edge_idx
277
-
278
- if dist[deficit_node] == np.inf:
304
+ # Relax edges from u
305
+ for v, eidx, is_rev, cost in graph[u]:
306
+ if residual_capacity[eidx] > 1e-10:
307
+ # Compute reduced cost
308
+ reduced_cost = cost + potential[u] - potential[v]
309
+ new_dist = dist[u] + reduced_cost
310
+
311
+ if new_dist < dist[v] - 1e-10:
312
+ dist[v] = new_dist
313
+ parent[v] = u
314
+ parent_edge[v] = eidx
315
+ parent_reverse[v] = is_rev
316
+
317
+ if dist[deficit_node] >= np.inf:
279
318
  # No path found
280
319
  break
281
320
 
282
- # Extract path and find bottleneck capacity
321
+ # Update potentials to maintain dual feasibility
322
+ for node in range(n_nodes):
323
+ if dist[node] < np.inf:
324
+ potential[node] += dist[node]
325
+
326
+ # Extract path by backtracking
283
327
  path_edges = []
328
+ path_reverse_flags = []
284
329
  node = deficit_node
285
- while parent[node] != -1:
330
+ path_length = 0
331
+ visited_set = set()
332
+
333
+ while parent[node] >= 0:
334
+ if path_length >= n_nodes:
335
+ break # Safety check
336
+ if node in visited_set:
337
+ break # Cycle detected
338
+
339
+ visited_set.add(node)
286
340
  path_edges.append(parent_edge[node])
341
+ path_reverse_flags.append(parent_reverse[node])
287
342
  node = parent[node]
343
+ path_length += 1
344
+
345
+ if not path_edges:
346
+ iteration += 1
347
+ continue
288
348
 
289
349
  path_edges.reverse()
350
+ path_reverse_flags.reverse()
290
351
 
291
- # Find minimum capacity along path
352
+ # Find bottleneck capacity
292
353
  min_flow = min(residual_capacity[e] for e in path_edges)
293
354
  min_flow = min(
294
- min_flow, current_supplies[excess_node], -current_supplies[deficit_node]
355
+ min_flow,
356
+ current_supplies[excess_node],
357
+ -current_supplies[deficit_node],
295
358
  )
296
359
 
297
360
  # Push flow along path
298
- total_cost = 0.0
299
- for edge_idx in path_edges:
300
- flow[edge_idx] += min_flow
301
- residual_capacity[edge_idx] -= min_flow
302
- total_cost += min_flow * edges[edge_idx].cost
361
+ for edge_idx, is_reverse in zip(path_edges, path_reverse_flags):
362
+ if is_reverse == 0:
363
+ # Forward edge: increase flow
364
+ flow[edge_idx] += min_flow
365
+ residual_capacity[edge_idx] -= min_flow
366
+ else:
367
+ # Reverse edge: decrease flow (cancel)
368
+ flow[edge_idx] -= min_flow
369
+ residual_capacity[edge_idx] += min_flow
303
370
 
304
371
  current_supplies[excess_node] -= min_flow
305
372
  current_supplies[deficit_node] += min_flow
306
373
 
307
374
  iteration += 1
308
375
 
309
- # Compute total cost
310
- total_cost = float(np.sum(flow[i] * edges[i].cost for i in range(n_edges)))
376
+ # Compute total cost: include all flows (including negative which cancel)
377
+ total_cost = 0.0
378
+ for i, edge in enumerate(edges):
379
+ total_cost += flow[i] * edge.cost
311
380
 
312
381
  # Determine status
313
- if np.allclose(current_supplies, 0):
382
+ if np.allclose(current_supplies, 0, atol=1e-6):
314
383
  status = FlowStatus.OPTIMAL
315
384
  elif iteration >= max_iterations:
316
385
  status = FlowStatus.TIMEOUT
@@ -409,6 +478,14 @@ def assignment_from_flow_solution(
409
478
  """
410
479
  Extract assignment from flow network solution.
411
480
 
481
+ A valid flow solution for assignment should have:
482
+ - Exactly 1 unit of flow from each worker to some task
483
+ - Exactly 1 unit of flow to each task from some worker
484
+ - No negative flows on worker->task edges (those are cancellations)
485
+
486
+ This function extracts the actual assignment by identifying which
487
+ worker->task edges carry the net positive flow.
488
+
412
489
  Parameters
413
490
  ----------
414
491
  flow : ndarray
@@ -427,24 +504,59 @@ def assignment_from_flow_solution(
427
504
  """
428
505
  m, n = cost_matrix_shape
429
506
  assignment = []
507
+ cost = 0.0
508
+
509
+ # Build source node (node 0) and sink node (node m+n+1) indices
510
+ source = 0
511
+ sink = m + n + 1
512
+
513
+ # For a valid assignment solution:
514
+ # - Count flow out of source to each worker
515
+ # - Count flow into sink from each task
516
+ worker_outflow = np.zeros(m)
517
+ task_inflow = np.zeros(n)
518
+
519
+ # Collect all worker->task edges and their flows
520
+ worker_task_edges = []
430
521
 
431
522
  for edge_idx, edge in enumerate(edges):
432
- # Worker-to-task edges: from_node in [1, m], to_node in [m+1, m+n]
433
- if 1 <= edge.from_node <= m and m + 1 <= edge.to_node <= m + n:
434
- if flow[edge_idx] > 0.5: # Flow > 0 (allowing for numerical tolerance)
435
- worker_idx = edge.from_node - 1
436
- task_idx = edge.to_node - m - 1
437
- assignment.append([worker_idx, task_idx])
523
+ # Worker edges: from source (0) to worker nodes (1..m)
524
+ if edge.from_node == source and 1 <= edge.to_node <= m:
525
+ worker_id = edge.to_node - 1
526
+ worker_outflow[worker_id] += flow[edge_idx]
438
527
 
439
- assignment = np.array(assignment, dtype=np.intp)
440
- cost = 0.0
441
- if len(assignment) > 0:
442
- cost = float(
443
- np.sum(
444
- flow[edge_idx] * edges[edge_idx].cost for edge_idx in range(len(edges))
445
- )
446
- )
528
+ # Task edges: from task nodes (m+1..m+n) to sink
529
+ if m + 1 <= edge.from_node <= m + n and edge.to_node == sink:
530
+ task_id = edge.from_node - (m + 1)
531
+ task_inflow[task_id] += flow[edge_idx]
447
532
 
533
+ # Worker-to-task edges
534
+ if 1 <= edge.from_node <= m and m + 1 <= edge.to_node <= m + n:
535
+ worker_id = edge.from_node - 1
536
+ task_id = edge.to_node - (m + 1)
537
+ if flow[edge_idx] > 0.5: # Positive flow means this edge is used
538
+ worker_task_edges.append(
539
+ {
540
+ "worker": worker_id,
541
+ "task": task_id,
542
+ "flow": flow[edge_idx],
543
+ "cost": edge.cost,
544
+ "edge_idx": edge_idx,
545
+ }
546
+ )
547
+
548
+ # For assignment problems, each worker should have exactly 1 outgoing flow
549
+ # and each task should have exactly 1 incoming flow
550
+ # Extract the assignment from worker->task edges with positive flow
551
+ for edge_info in worker_task_edges:
552
+ assignment.append([edge_info["worker"], edge_info["task"]])
553
+ cost += edge_info["flow"] * edge_info["cost"]
554
+
555
+ assignment = (
556
+ np.array(assignment, dtype=np.intp)
557
+ if assignment
558
+ else np.empty((0, 2), dtype=np.intp)
559
+ )
448
560
  return assignment, cost
449
561
 
450
562
 
@@ -269,6 +269,13 @@ def mjd_to_jd(mjd: float) -> float:
269
269
  float
270
270
  Julian Date.
271
271
 
272
+ Examples
273
+ --------
274
+ >>> mjd = 44239.0 # 1980-01-01
275
+ >>> jd = mjd_to_jd(mjd)
276
+ >>> jd
277
+ 2444239.5
278
+
272
279
  Notes
273
280
  -----
274
281
  MJD = JD - 2400000.5
@@ -289,6 +296,13 @@ def jd_to_mjd(jd: float) -> float:
289
296
  -------
290
297
  float
291
298
  Modified Julian Date.
299
+
300
+ Examples
301
+ --------
302
+ >>> jd = 2444239.5 # 1980-01-01
303
+ >>> mjd = jd_to_mjd(jd)
304
+ >>> mjd
305
+ 44239.0
292
306
  """
293
307
  return jd - MJD_OFFSET
294
308
 
@@ -328,6 +342,13 @@ def jd_to_unix(jd: float) -> float:
328
342
  -------
329
343
  float
330
344
  Unix timestamp.
345
+
346
+ Examples
347
+ --------
348
+ >>> jd = 2440587.5 # 1970-01-01 00:00:00 UTC
349
+ >>> unix_to_jd = jd_to_unix(jd)
350
+ >>> unix_to_jd
351
+ 0.0
331
352
  """
332
353
  return (jd - JD_UNIX_EPOCH) * 86400.0
333
354
 
@@ -94,6 +94,23 @@ def compute_cluster_centroid(
94
94
  -------
95
95
  centroid : ndarray
96
96
  Centroid position [x, y].
97
+
98
+ Examples
99
+ --------
100
+ >>> from pytcl.trackers.multi_target import Track
101
+ >>> import numpy as np
102
+ >>> # Create sample tracks with [x, vx, y, vy] state vectors
103
+ >>> track1 = Track(state=np.array([0.0, 1.0, 0.0, 1.0]))
104
+ >>> track2 = Track(state=np.array([2.0, 1.0, 2.0, 1.0]))
105
+ >>> track3 = Track(state=np.array([4.0, 1.0, 4.0, 1.0]))
106
+ >>> tracks = [track1, track2, track3]
107
+ >>> centroid = compute_cluster_centroid(tracks)
108
+ >>> centroid
109
+ array([2., 2.])
110
+
111
+ See Also
112
+ --------
113
+ compute_cluster_covariance : Compute covariance of track positions.
97
114
  """
98
115
  track_list = list(tracks)
99
116
  if len(track_list) == 0:
@@ -122,6 +139,25 @@ def compute_cluster_covariance(
122
139
  -------
123
140
  covariance : ndarray
124
141
  Position covariance matrix (2x2).
142
+
143
+ Examples
144
+ --------
145
+ >>> from pytcl.trackers.multi_target import Track
146
+ >>> import numpy as np
147
+ >>> # Create collinear tracks (high variance along x-axis)
148
+ >>> track1 = Track(state=np.array([0.0, 1.0, 0.0, 0.0]))
149
+ >>> track2 = Track(state=np.array([1.0, 1.0, 0.0, 0.0]))
150
+ >>> track3 = Track(state=np.array([2.0, 1.0, 0.0, 0.0]))
151
+ >>> tracks = [track1, track2, track3]
152
+ >>> cov = compute_cluster_covariance(tracks)
153
+ >>> cov.shape
154
+ (2, 2)
155
+ >>> cov[0, 0] > cov[1, 1] # More spread in x than y
156
+ True
157
+
158
+ See Also
159
+ --------
160
+ compute_cluster_centroid : Compute centroid of track positions.
125
161
  """
126
162
  track_list = list(tracks)
127
163
  if len(track_list) < 2: