nrl-tracker 1.7.5__tar.gz → 1.9.0__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 (233) hide show
  1. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/CONTRIBUTING.md +115 -30
  2. {nrl_tracker-1.7.5/nrl_tracker.egg-info → nrl_tracker-1.9.0}/PKG-INFO +2 -2
  3. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/README.md +1 -1
  4. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0/nrl_tracker.egg-info}/PKG-INFO +2 -2
  5. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/nrl_tracker.egg-info/SOURCES.txt +8 -0
  6. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pyproject.toml +1 -1
  7. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/__init__.py +3 -3
  8. nrl_tracker-1.9.0/pytcl/assignment_algorithms/dijkstra_min_cost.py +183 -0
  9. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/network_flow.py +94 -1
  10. nrl_tracker-1.9.0/pytcl/assignment_algorithms/network_simplex.py +165 -0
  11. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/ephemerides.py +8 -4
  12. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/relativity.py +20 -0
  13. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/__init__.py +19 -8
  14. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/base.py +82 -9
  15. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/covertree.py +14 -21
  16. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/kd_tree.py +18 -45
  17. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/rtree.py +43 -4
  18. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/vptree.py +14 -21
  19. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/core/__init__.py +59 -2
  20. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/core/constants.py +59 -0
  21. nrl_tracker-1.9.0/pytcl/core/exceptions.py +865 -0
  22. nrl_tracker-1.9.0/pytcl/core/optional_deps.py +531 -0
  23. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/core/validation.py +4 -6
  24. nrl_tracker-1.9.0/pytcl/dynamic_estimation/kalman/matrix_utils.py +427 -0
  25. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/square_root.py +20 -213
  26. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/sr_ukf.py +5 -5
  27. nrl_tracker-1.9.0/pytcl/dynamic_estimation/kalman/types.py +98 -0
  28. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/signal_processing/detection.py +19 -0
  29. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/transforms/wavelets.py +7 -6
  30. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/plotting/coordinates.py +25 -27
  31. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/plotting/ellipses.py +14 -16
  32. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/plotting/metrics.py +7 -5
  33. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/plotting/tracks.py +8 -7
  34. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/terrain/loaders.py +10 -6
  35. nrl_tracker-1.9.0/tests/test_exceptions.py +328 -0
  36. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_network_flow.py +0 -13
  37. nrl_tracker-1.9.0/tests/test_optional_deps.py +361 -0
  38. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/LICENSE +0 -0
  39. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/MANIFEST.in +0 -0
  40. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/nrl_tracker.egg-info/dependency_links.txt +0 -0
  41. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/nrl_tracker.egg-info/requires.txt +0 -0
  42. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/nrl_tracker.egg-info/top_level.txt +0 -0
  43. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/__init__.py +0 -0
  44. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/data_association.py +0 -0
  45. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/gating.py +0 -0
  46. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/jpda.py +0 -0
  47. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/nd_assignment.py +0 -0
  48. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/three_dimensional/__init__.py +0 -0
  49. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/three_dimensional/assignment.py +0 -0
  50. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/two_dimensional/__init__.py +0 -0
  51. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/two_dimensional/assignment.py +0 -0
  52. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/assignment_algorithms/two_dimensional/kbest.py +0 -0
  53. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/__init__.py +0 -0
  54. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/lambert.py +0 -0
  55. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/orbital_mechanics.py +0 -0
  56. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/reference_frames.py +0 -0
  57. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/sgp4.py +0 -0
  58. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/special_orbits.py +0 -0
  59. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/time_systems.py +0 -0
  60. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/astronomical/tle.py +0 -0
  61. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/atmosphere/__init__.py +0 -0
  62. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/atmosphere/ionosphere.py +0 -0
  63. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/atmosphere/models.py +0 -0
  64. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/atmosphere/nrlmsise00.py +0 -0
  65. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/clustering/__init__.py +0 -0
  66. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/clustering/dbscan.py +0 -0
  67. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/clustering/gaussian_mixture.py +0 -0
  68. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/clustering/hierarchical.py +0 -0
  69. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/clustering/kmeans.py +0 -0
  70. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/cluster_set.py +0 -0
  71. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/measurement_set.py +0 -0
  72. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/containers/track_list.py +0 -0
  73. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/__init__.py +0 -0
  74. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/conversions/__init__.py +0 -0
  75. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/conversions/geodetic.py +0 -0
  76. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/conversions/spherical.py +0 -0
  77. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/jacobians/__init__.py +0 -0
  78. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/jacobians/jacobians.py +0 -0
  79. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/projections/__init__.py +0 -0
  80. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/projections/projections.py +0 -0
  81. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/rotations/__init__.py +0 -0
  82. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/coordinate_systems/rotations/rotations.py +0 -0
  83. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/core/array_utils.py +0 -0
  84. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/__init__.py +0 -0
  85. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/batch_estimation/__init__.py +0 -0
  86. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/gaussian_sum_filter.py +0 -0
  87. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/imm.py +0 -0
  88. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/information_filter.py +0 -0
  89. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/__init__.py +0 -0
  90. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/constrained.py +0 -0
  91. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/extended.py +0 -0
  92. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/h_infinity.py +0 -0
  93. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/linear.py +0 -0
  94. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/ud_filter.py +0 -0
  95. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/kalman/unscented.py +0 -0
  96. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/measurement_update/__init__.py +0 -0
  97. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/particle_filters/__init__.py +0 -0
  98. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/particle_filters/bootstrap.py +0 -0
  99. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/rbpf.py +0 -0
  100. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_estimation/smoothers.py +0 -0
  101. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/__init__.py +0 -0
  102. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/continuous_time/__init__.py +0 -0
  103. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/continuous_time/dynamics.py +0 -0
  104. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/discrete_time/__init__.py +0 -0
  105. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/discrete_time/coordinated_turn.py +0 -0
  106. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/discrete_time/polynomial.py +0 -0
  107. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/discrete_time/singer.py +0 -0
  108. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/process_noise/__init__.py +0 -0
  109. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/process_noise/coordinated_turn.py +0 -0
  110. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/process_noise/polynomial.py +0 -0
  111. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/dynamic_models/process_noise/singer.py +0 -0
  112. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/__init__.py +0 -0
  113. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/clenshaw.py +0 -0
  114. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/egm.py +0 -0
  115. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/models.py +0 -0
  116. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/spherical_harmonics.py +0 -0
  117. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/gravity/tides.py +0 -0
  118. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/logging_config.py +0 -0
  119. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/magnetism/__init__.py +0 -0
  120. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/magnetism/emm.py +0 -0
  121. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/magnetism/igrf.py +0 -0
  122. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/magnetism/wmm.py +0 -0
  123. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/__init__.py +0 -0
  124. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/basic_matrix/__init__.py +0 -0
  125. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/basic_matrix/decompositions.py +0 -0
  126. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/basic_matrix/special_matrices.py +0 -0
  127. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/combinatorics/__init__.py +0 -0
  128. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/combinatorics/combinatorics.py +0 -0
  129. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/continuous_optimization/__init__.py +0 -0
  130. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/geometry/__init__.py +0 -0
  131. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/geometry/geometry.py +0 -0
  132. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/interpolation/__init__.py +0 -0
  133. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/interpolation/interpolation.py +0 -0
  134. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/numerical_integration/__init__.py +0 -0
  135. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/numerical_integration/quadrature.py +0 -0
  136. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/polynomials/__init__.py +0 -0
  137. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/signal_processing/__init__.py +0 -0
  138. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/signal_processing/filters.py +0 -0
  139. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/signal_processing/matched_filter.py +0 -0
  140. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/__init__.py +0 -0
  141. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/bessel.py +0 -0
  142. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/debye.py +0 -0
  143. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/elliptic.py +0 -0
  144. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/error_functions.py +0 -0
  145. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/gamma_functions.py +0 -0
  146. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/hypergeometric.py +0 -0
  147. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/lambert_w.py +0 -0
  148. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/special_functions/marcum_q.py +0 -0
  149. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/statistics/__init__.py +0 -0
  150. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/statistics/distributions.py +0 -0
  151. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/statistics/estimators.py +0 -0
  152. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/transforms/__init__.py +0 -0
  153. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/transforms/fourier.py +0 -0
  154. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/mathematical_functions/transforms/stft.py +0 -0
  155. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/misc/__init__.py +0 -0
  156. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/__init__.py +0 -0
  157. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/geodesy.py +0 -0
  158. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/great_circle.py +0 -0
  159. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/ins.py +0 -0
  160. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/ins_gnss.py +0 -0
  161. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/navigation/rhumb.py +0 -0
  162. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/performance_evaluation/__init__.py +0 -0
  163. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/performance_evaluation/estimation_metrics.py +0 -0
  164. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/performance_evaluation/track_metrics.py +0 -0
  165. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/physical_values/__init__.py +0 -0
  166. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/plotting/__init__.py +0 -0
  167. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/scheduling/__init__.py +0 -0
  168. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/static_estimation/__init__.py +0 -0
  169. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/static_estimation/least_squares.py +0 -0
  170. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/static_estimation/maximum_likelihood.py +0 -0
  171. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/static_estimation/robust.py +0 -0
  172. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/terrain/__init__.py +0 -0
  173. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/terrain/dem.py +0 -0
  174. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/terrain/visibility.py +0 -0
  175. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/trackers/__init__.py +0 -0
  176. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/trackers/hypothesis.py +0 -0
  177. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/trackers/mht.py +0 -0
  178. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/trackers/multi_target.py +0 -0
  179. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/trackers/single_target.py +0 -0
  180. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/pytcl/transponders/__init__.py +0 -0
  181. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/setup.cfg +0 -0
  182. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/__init__.py +0 -0
  183. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/conftest.py +0 -0
  184. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_additional_trees.py +0 -0
  185. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_assignment_algorithms.py +0 -0
  186. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_astronomical.py +0 -0
  187. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_clustering.py +0 -0
  188. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_constrained_ekf.py +0 -0
  189. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_coordinate_systems.py +0 -0
  190. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_coverage_boost.py +0 -0
  191. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_coverage_boost_2.py +0 -0
  192. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_dynamic_models.py +0 -0
  193. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_egm.py +0 -0
  194. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_emm.py +0 -0
  195. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_ephemerides.py +0 -0
  196. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_gaussian_mixtures.py +0 -0
  197. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_gaussian_sum_filter.py +0 -0
  198. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_geophysical.py +0 -0
  199. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_great_circle.py +0 -0
  200. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_h_infinity.py +0 -0
  201. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_ins.py +0 -0
  202. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_ins_gnss.py +0 -0
  203. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_jpda.py +0 -0
  204. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_kalman_filters.py +0 -0
  205. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_mathematical_functions.py +0 -0
  206. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_maximum_likelihood.py +0 -0
  207. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_mht.py +0 -0
  208. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_nd_assignment.py +0 -0
  209. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_nrlmsise00.py +0 -0
  210. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_performance_evaluation.py +0 -0
  211. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_phase6_specialized.py +0 -0
  212. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_plotting.py +0 -0
  213. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_projections.py +0 -0
  214. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_rbpf.py +0 -0
  215. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_relativity.py +0 -0
  216. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_rhumb.py +0 -0
  217. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_sgp4.py +0 -0
  218. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_signal_processing.py +0 -0
  219. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_smoothers.py +0 -0
  220. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_spatial_containers_parametrized.py +0 -0
  221. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_spatial_structures.py +0 -0
  222. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_special_functions.py +0 -0
  223. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_special_orbits.py +0 -0
  224. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_static_estimation.py +0 -0
  225. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_terrain.py +0 -0
  226. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_terrain_loaders.py +0 -0
  227. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_tides.py +0 -0
  228. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_tod_mod.py +0 -0
  229. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_trackers.py +0 -0
  230. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_tracking_containers.py +0 -0
  231. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_transforms.py +0 -0
  232. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/test_validation.py +0 -0
  233. {nrl_tracker-1.7.5 → nrl_tracker-1.9.0}/tests/unit/test_core.py +0 -0
@@ -220,26 +220,57 @@ When porting a function from the original MATLAB library:
220
220
  - Reference any related issues
221
221
  - Ensure CI passes
222
222
 
223
- ## Priority Areas
223
+ ## Current Development Status
224
224
 
225
- If you're looking for ways to contribute, these areas are priorities:
225
+ **Version:** v1.9.0
226
+ **MATLAB Parity:** 100% ✅
227
+ **Test Suite:** 2,133 tests passing
228
+ **Code Coverage:** 76% (target 80%+ in v2.0.0)
229
+ **Quality:** 100% compliance (black, isort, flake8, mypy --strict)
226
230
 
227
- ### High Priority
228
- - Coordinate system conversions (`coordinate_systems/conversions/`)
229
- - Basic Kalman filter implementation (`dynamic_estimation/kalman/`)
230
- - Constant velocity/acceleration models (`dynamic_models/discrete_time/`)
231
- - Hungarian algorithm for assignment (`assignment_algorithms/`)
231
+ ## v2.0.0 Roadmap - 8 Phases Over 18 Months
232
232
 
233
- ### Medium Priority
234
- - UKF and EKF implementations
235
- - Coordinated turn models
236
- - JPDA data association
237
- - OSPA metric
233
+ ### Phase 1: Network Flow Performance (NEXT)
234
+ **Focus:** Replace Bellman-Ford O(VE²) with network simplex O(VE log V)
235
+ - **Impact:** 50-100x faster network flow computations
236
+ - **Location:** `pytcl/assignment/network_flow.py`
237
+ - **Tests:** Will re-enable 13 currently skipped tests
238
+ - **Estimated:** 2-3 weeks
238
239
 
239
- ### Lower Priority
240
+ ### Phases 2-5: Algorithm Optimization
241
+ - Phase 2: Kalman filter performance
242
+ - Phase 3: Tracking algorithm improvements
243
+ - Phase 4: Signal processing optimization
244
+ - Phase 5: Advanced estimation methods
245
+
246
+ ### Phase 6: Test Expansion
247
+ - **Goal:** +50 new tests, target 80%+ coverage
248
+ - **Focus:** Edge cases, numerical stability, batch operations
249
+
250
+ ### Phases 7-8: Documentation & Final Polish
251
+ - Phase 7: Documentation updates and examples
252
+ - Phase 8: Performance tuning and optimization
253
+
254
+ ## Priority Areas for Contributors
255
+
256
+ If you're looking for ways to contribute:
257
+
258
+ ### High Priority (v2.0.0 Phase 1)
259
+ - Network flow algorithm optimization (`assignment/network_flow.py`)
260
+ - Performance profiling and benchmarking
261
+ - Algorithm optimization and refactoring
262
+
263
+ ### Medium Priority
264
+ - New test cases (especially edge cases)
265
+ - Documentation improvements
266
+ - Example script enhancements
267
+ - Bug fixes and code review
268
+
269
+ ### Other Areas
240
270
  - Astronomical code (consider using astropy)
241
271
  - Gravity/magnetism models
242
272
  - Terrain models
273
+ - Domain-specific optimizations
243
274
 
244
275
  ## Release Process
245
276
 
@@ -249,15 +280,33 @@ When preparing a new release, follow these steps:
249
280
 
250
281
  Update the version in these files:
251
282
  - `pyproject.toml` - `version = "X.Y.Z"`
252
- - `docs/conf.py` - `release = "X.Y.Z"`
253
- - `docs/_static/landing.html` - Update the status badge version
283
+ - `pytcl/__init__.py` - `__version__ = "X.Y.Z"`
284
+ - `CHANGELOG.md` - Add new version entry at top
285
+ - `ROADMAP.md` - Update version references if applicable
254
286
 
255
- ### 2. Update Landing Page Statistics
287
+ ### 2. Verify Current Metrics
288
+
289
+ Before release, verify these metrics:
290
+ ```bash
291
+ # Count functions
292
+ grep -r "^def " pytcl/ | wc -l
293
+
294
+ # Count modules
295
+ find pytcl -name "*.py" -type f | wc -l
296
+
297
+ # Run tests with collection
298
+ pytest --collect-only -q | tail -1
299
+
300
+ # Get coverage
301
+ pytest --cov=pytcl --cov-report=term
302
+ ```
256
303
 
257
- In `docs/_static/landing.html`, update the statistics to reflect current metrics:
258
- - **Version badge** (line ~730): `vX.Y.Z — 720+ Functions`
259
- - **Test count** (line ~766): Run `pytest --collect-only` to get current test count
260
- - **Other stats** as needed (functions, modules, etc.)
304
+ Current metrics (v1.9.0):
305
+ - **Functions:** 1,070+
306
+ - **Modules:** 150+
307
+ - **Tests:** 2,133 (all passing)
308
+ - **Coverage:** 76%
309
+ - **MATLAB Parity:** 100%
261
310
 
262
311
  ### 3. Sync Examples
263
312
 
@@ -271,19 +320,25 @@ cp examples/*.py docs/examples/
271
320
 
272
321
  ```bash
273
322
  # Sort imports
274
- isort pytcl tests examples docs/examples
323
+ isort pytcl tests examples docs/examples scripts
275
324
 
276
325
  # Format code
277
326
  black .
278
327
 
279
328
  # Lint
280
- flake8 pytcl tests examples docs/examples
329
+ flake8 pytcl tests examples docs/examples scripts
281
330
 
282
- # Type check
283
- mypy pytcl examples docs/examples
331
+ # Type check (strict mode)
332
+ mypy --strict pytcl
284
333
 
285
334
  # Run full test suite with coverage
286
- pytest --cov=pytcl --cov-report=term-missing
335
+ pytest tests/ --cov=pytcl --cov-report=term-missing
336
+
337
+ # Run benchmark tests
338
+ pytest benchmarks/ -v
339
+
340
+ # Verify all pass
341
+ echo "All checks complete!"
287
342
  ```
288
343
 
289
344
  ### 5. Verify Examples Run
@@ -315,19 +370,49 @@ Update both `ROADMAP.md` and `docs/roadmap.rst`:
315
370
  - Ensure all new features are documented
316
371
  - Rebuild docs locally to verify: `cd docs && make html`
317
372
 
318
- ### 8. Create Release Commit
373
+ ### 8. Create Release Commit and Tag
319
374
 
320
375
  ```bash
376
+ # Stage all changes
321
377
  git add -A
322
- git commit -m "Release vX.Y.Z: <brief description>"
323
- git tag vX.Y.Z
324
- git push origin main --tags
378
+
379
+ # Create commit with comprehensive message
380
+ git commit -m "vX.Y.Z: Release description
381
+
382
+ - Feature 1
383
+ - Feature 2
384
+ - Bug fix 1
385
+ - Documentation updates
386
+
387
+ Quality metrics:
388
+ - Tests: #### passed
389
+ - Coverage: ##%
390
+ - MATLAB Parity: 100%"
391
+
392
+ # Create annotated tag with release notes
393
+ git tag -a vX.Y.Z -m "vX.Y.Z - Release Title
394
+
395
+ Release description and highlights"
396
+
397
+ # Push commits and tags
398
+ git push origin main
399
+ git push origin vX.Y.Z
400
+ ```
401
+
402
+ ### 9. Create GitHub Release
403
+
404
+ ```bash
405
+ # Use GitHub CLI to create release
406
+ gh release create vX.Y.Z --title "vX.Y.Z - Release Title" --notes-file release_notes.md
325
407
  ```
326
408
 
327
- ### 9. Publish to PyPI
409
+ ### 10. Publish to PyPI (Optional)
328
410
 
329
411
  ```bash
412
+ # Build distribution
330
413
  python -m build
414
+
415
+ # Upload to PyPI (requires credentials)
331
416
  twine upload dist/*
332
417
  ```
333
418
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.7.5
3
+ Version: 1.9.0
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
@@ -63,7 +63,7 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
63
63
 
64
64
  # Tracker Component Library (Python)
65
65
 
66
- [![PyPI version](https://img.shields.io/badge/pypi-v1.7.2-blue.svg)](https://pypi.org/project/nrl-tracker/)
66
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.9.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
67
67
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
68
68
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
69
69
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
@@ -1,6 +1,6 @@
1
1
  # Tracker Component Library (Python)
2
2
 
3
- [![PyPI version](https://img.shields.io/badge/pypi-v1.7.2-blue.svg)](https://pypi.org/project/nrl-tracker/)
3
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.9.0-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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nrl-tracker
3
- Version: 1.7.5
3
+ Version: 1.9.0
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
@@ -63,7 +63,7 @@ Requires-Dist: nrl-tracker[astronomy,dev,geodesy,optimization,signal,visualizati
63
63
 
64
64
  # Tracker Component Library (Python)
65
65
 
66
- [![PyPI version](https://img.shields.io/badge/pypi-v1.7.2-blue.svg)](https://pypi.org/project/nrl-tracker/)
66
+ [![PyPI version](https://img.shields.io/badge/pypi-v1.9.0-blue.svg)](https://pypi.org/project/nrl-tracker/)
67
67
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
68
68
  [![License: Public Domain](https://img.shields.io/badge/License-Public%20Domain-brightgreen.svg)](https://en.wikipedia.org/wiki/Public_domain)
69
69
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
@@ -12,10 +12,12 @@ pytcl/__init__.py
12
12
  pytcl/logging_config.py
13
13
  pytcl/assignment_algorithms/__init__.py
14
14
  pytcl/assignment_algorithms/data_association.py
15
+ pytcl/assignment_algorithms/dijkstra_min_cost.py
15
16
  pytcl/assignment_algorithms/gating.py
16
17
  pytcl/assignment_algorithms/jpda.py
17
18
  pytcl/assignment_algorithms/nd_assignment.py
18
19
  pytcl/assignment_algorithms/network_flow.py
20
+ pytcl/assignment_algorithms/network_simplex.py
19
21
  pytcl/assignment_algorithms/three_dimensional/__init__.py
20
22
  pytcl/assignment_algorithms/three_dimensional/assignment.py
21
23
  pytcl/assignment_algorithms/two_dimensional/__init__.py
@@ -62,6 +64,8 @@ pytcl/coordinate_systems/rotations/rotations.py
62
64
  pytcl/core/__init__.py
63
65
  pytcl/core/array_utils.py
64
66
  pytcl/core/constants.py
67
+ pytcl/core/exceptions.py
68
+ pytcl/core/optional_deps.py
65
69
  pytcl/core/validation.py
66
70
  pytcl/dynamic_estimation/__init__.py
67
71
  pytcl/dynamic_estimation/gaussian_sum_filter.py
@@ -75,8 +79,10 @@ pytcl/dynamic_estimation/kalman/constrained.py
75
79
  pytcl/dynamic_estimation/kalman/extended.py
76
80
  pytcl/dynamic_estimation/kalman/h_infinity.py
77
81
  pytcl/dynamic_estimation/kalman/linear.py
82
+ pytcl/dynamic_estimation/kalman/matrix_utils.py
78
83
  pytcl/dynamic_estimation/kalman/square_root.py
79
84
  pytcl/dynamic_estimation/kalman/sr_ukf.py
85
+ pytcl/dynamic_estimation/kalman/types.py
80
86
  pytcl/dynamic_estimation/kalman/ud_filter.py
81
87
  pytcl/dynamic_estimation/kalman/unscented.py
82
88
  pytcl/dynamic_estimation/measurement_update/__init__.py
@@ -182,6 +188,7 @@ tests/test_dynamic_models.py
182
188
  tests/test_egm.py
183
189
  tests/test_emm.py
184
190
  tests/test_ephemerides.py
191
+ tests/test_exceptions.py
185
192
  tests/test_gaussian_mixtures.py
186
193
  tests/test_gaussian_sum_filter.py
187
194
  tests/test_geophysical.py
@@ -197,6 +204,7 @@ tests/test_mht.py
197
204
  tests/test_nd_assignment.py
198
205
  tests/test_network_flow.py
199
206
  tests/test_nrlmsise00.py
207
+ tests/test_optional_deps.py
200
208
  tests/test_performance_evaluation.py
201
209
  tests/test_phase6_specialized.py
202
210
  tests/test_plotting.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nrl-tracker"
7
- version = "1.7.5"
7
+ version = "1.9.0"
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,8 +6,8 @@ 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.7.4 (January 4, 2026)
10
- **Status:** Production-ready, 2,057 tests passing, 76% line coverage
9
+ **Current Version:** 1.9.0 (January 4, 2026)
10
+ **Status:** Production-ready, 2,133 tests passing, 76% line coverage
11
11
  Examples
12
12
  --------
13
13
  >>> import pytcl as pytcl
@@ -21,7 +21,7 @@ References
21
21
  no. 5, pp. 18-27, May 2017.
22
22
  """
23
23
 
24
- __version__ = "1.7.5"
24
+ __version__ = "1.9.0"
25
25
  __author__ = "Python Port Contributors"
26
26
  __original_author__ = "David F. Crouse, Naval Research Laboratory"
27
27
 
@@ -0,0 +1,183 @@
1
+ """
2
+ Dijkstra-based minimum cost flow using potentials (Johnson's algorithm).
3
+
4
+ This implements the successive shortest paths algorithm using Dijkstra's algorithm
5
+ instead of Bellman-Ford, which is much faster when costs can be non-negative
6
+ after potential adjustments.
7
+
8
+ Algorithm:
9
+ 1. Maintain node potentials that preserve optimality
10
+ 2. Use potentials to ensure all edge costs are non-negative
11
+ 3. Run Dijkstra (O(E log V)) instead of Bellman-Ford (O(VE))
12
+ 4. Update potentials after each shortest path
13
+
14
+ Time complexity: O(K * E log V) where K is number of shortest paths needed
15
+ Space complexity: O(V + E)
16
+
17
+ This is based on:
18
+ - Johnson's algorithm for all-pairs shortest paths
19
+ - Successive shortest paths with potentials
20
+ - Published in: "Efficient Implementation of the Bellman-Ford Algorithm"
21
+ """
22
+
23
+ import heapq
24
+ from typing import Any
25
+
26
+ import numpy as np
27
+ from numpy.typing import NDArray
28
+
29
+
30
+ def min_cost_flow_dijkstra_potentials(
31
+ n_nodes: int,
32
+ edges: list[tuple[int, int, float, float]],
33
+ supplies: NDArray[np.float64],
34
+ max_iterations: int = 1000,
35
+ ) -> tuple[NDArray[np.float64], float, int]:
36
+ """
37
+ Solve min-cost flow using Dijkstra with potentials.
38
+
39
+ Uses Johnson's method to maintain non-negative reduced costs,
40
+ allowing efficient Dijkstra instead of Bellman-Ford.
41
+
42
+ Parameters
43
+ ----------
44
+ n_nodes : int
45
+ Number of nodes
46
+ edges : list of tuple
47
+ Each tuple is (from_node, to_node, capacity, cost)
48
+ supplies : ndarray
49
+ Supply/demand for each node
50
+ max_iterations : int
51
+ Maximum iterations
52
+
53
+ Returns
54
+ -------
55
+ flow : ndarray
56
+ Flow on each edge
57
+ total_cost : float
58
+ Total cost
59
+ iterations : int
60
+ Iterations used
61
+ """
62
+ # Build edge structures
63
+ graph: list[list[int]] = [[] for _ in range(n_nodes)]
64
+ edge_data: list[dict[str, Any]] = []
65
+
66
+ for idx, (u, v, cap, cost) in enumerate(edges):
67
+ edge_data.append(
68
+ {
69
+ "from": u,
70
+ "to": v,
71
+ "capacity": cap,
72
+ "cost": float(cost),
73
+ "flow": 0.0,
74
+ }
75
+ )
76
+ graph[u].append(idx)
77
+
78
+ # Initialize potentials to zero
79
+ potential = np.zeros(n_nodes)
80
+
81
+ # Single Bellman-Ford pass to initialize potentials
82
+ # This ensures all reduced costs are non-negative at start
83
+ for _ in range(n_nodes - 1):
84
+ for u in range(n_nodes):
85
+ for edge_idx in graph[u]:
86
+ e = edge_data[edge_idx]
87
+ v = e["to"]
88
+ if e["flow"] < e["capacity"] - 1e-10:
89
+ reduced = e["cost"] + potential[u] - potential[v]
90
+ if reduced < -1e-10:
91
+ potential[v] = potential[u] + e["cost"]
92
+
93
+ # Main loop
94
+ current_supplies = supplies.copy()
95
+ iteration = 0
96
+
97
+ for iteration in range(max_iterations):
98
+ # Find source (excess) and sink (deficit) nodes
99
+ source = -1
100
+ sink = -1
101
+
102
+ for node in range(n_nodes):
103
+ if current_supplies[node] > 1e-10 and source == -1:
104
+ source = node
105
+ if current_supplies[node] < -1e-10 and sink == -1:
106
+ sink = node
107
+
108
+ if source == -1 or sink == -1:
109
+ break
110
+
111
+ # Dijkstra with potentials
112
+ dist = np.full(n_nodes, np.inf)
113
+ dist[source] = 0.0
114
+ parent = np.full(n_nodes, -1, dtype=int)
115
+ parent_edge = np.full(n_nodes, -1, dtype=int)
116
+
117
+ pq = [(0.0, source)]
118
+ visited = set()
119
+
120
+ while pq:
121
+ d, u = heapq.heappop(pq)
122
+
123
+ if u in visited:
124
+ continue
125
+ visited.add(u)
126
+
127
+ if d > dist[u] + 1e-10:
128
+ continue
129
+
130
+ for edge_idx in graph[u]:
131
+ e = edge_data[edge_idx]
132
+ v = e["to"]
133
+
134
+ if e["flow"] < e["capacity"] - 1e-10:
135
+ # Reduced cost using potentials
136
+ reduced = e["cost"] + potential[u] - potential[v]
137
+ new_dist = dist[u] + reduced
138
+
139
+ if new_dist < dist[v] - 1e-10:
140
+ dist[v] = new_dist
141
+ parent[v] = u
142
+ parent_edge[v] = edge_idx
143
+ heapq.heappush(pq, (new_dist, v))
144
+
145
+ if dist[sink] == np.inf:
146
+ break
147
+
148
+ # Extract path
149
+ path_edges = []
150
+ node = sink
151
+ while parent[node] != -1:
152
+ path_edges.append(parent_edge[node])
153
+ node = parent[node]
154
+ path_edges.reverse()
155
+
156
+ # Find bottleneck
157
+ min_flow = min(
158
+ edge_data[e]["capacity"] - edge_data[e]["flow"] for e in path_edges
159
+ )
160
+ min_flow = min(
161
+ min_flow,
162
+ current_supplies[source],
163
+ -current_supplies[sink],
164
+ )
165
+
166
+ # Push flow
167
+ for edge_idx in path_edges:
168
+ edge_data[edge_idx]["flow"] += min_flow
169
+
170
+ current_supplies[source] -= min_flow
171
+ current_supplies[sink] += min_flow
172
+
173
+ # Update potentials for next iteration
174
+ # New potential = old potential + distance from Dijkstra
175
+ for node in range(n_nodes):
176
+ if dist[node] < np.inf:
177
+ potential[node] += dist[node]
178
+
179
+ # Extract solution
180
+ result_flow = np.array([e["flow"] for e in edge_data])
181
+ total_cost = sum(e["flow"] * e["cost"] for e in edge_data)
182
+
183
+ return result_flow, total_cost, iteration + 1
@@ -297,6 +297,82 @@ def min_cost_flow_successive_shortest_paths(
297
297
  )
298
298
 
299
299
 
300
+ def min_cost_flow_simplex(
301
+ edges: list[FlowEdge],
302
+ supplies: NDArray[np.float64],
303
+ max_iterations: int = 10000,
304
+ ) -> MinCostFlowResult:
305
+ """
306
+ Solve min-cost flow using Dijkstra-based successive shortest paths.
307
+
308
+ This optimized version uses:
309
+ - Dijkstra's algorithm (O(E log V)) instead of Bellman-Ford (O(VE))
310
+ - Node potentials to maintain non-negative edge costs
311
+ - Johnson's technique for cost adjustment
312
+
313
+ This is significantly faster than Bellman-Ford while maintaining
314
+ guaranteed correctness and optimality.
315
+
316
+ Time complexity: O(K * E log V) where K = number of shortest paths
317
+ Space complexity: O(V + E)
318
+
319
+ Parameters
320
+ ----------
321
+ edges : list[FlowEdge]
322
+ List of edges with capacities and costs.
323
+ supplies : ndarray
324
+ Supply/demand at each node.
325
+ max_iterations : int, optional
326
+ Maximum iterations (default 10000).
327
+
328
+ Returns
329
+ -------
330
+ MinCostFlowResult
331
+ Solution with flow values, cost, status, and iterations.
332
+
333
+ References
334
+ ----------
335
+ .. [1] Ahuja, R. K., Magnanti, T. L., & Orlin, J. B. (1993).
336
+ Network Flows: Theory, Algorithms, and Applications.
337
+ (Chapter on successive shortest paths with potentials)
338
+ .. [2] Johnson, D. B. (1977).
339
+ Efficient All-Pairs Shortest Paths in Weighted Graphs.
340
+ """
341
+ from pytcl.assignment_algorithms.dijkstra_min_cost import (
342
+ min_cost_flow_dijkstra_potentials,
343
+ )
344
+
345
+ n_nodes = len(supplies)
346
+
347
+ # Convert FlowEdge objects to tuples
348
+ edge_tuples = [(e.from_node, e.to_node, e.capacity, e.cost) for e in edges]
349
+
350
+ # Run optimized Dijkstra-based algorithm
351
+ flow, total_cost, iterations = min_cost_flow_dijkstra_potentials(
352
+ n_nodes, edge_tuples, supplies, max_iterations
353
+ )
354
+
355
+ # Check feasibility
356
+ residual_supplies = supplies.copy()
357
+ for i, edge in enumerate(edges):
358
+ residual_supplies[edge.from_node] -= flow[i]
359
+ residual_supplies[edge.to_node] += flow[i]
360
+
361
+ if np.allclose(residual_supplies, 0, atol=1e-6):
362
+ status = FlowStatus.OPTIMAL
363
+ elif iterations >= max_iterations:
364
+ status = FlowStatus.TIMEOUT
365
+ else:
366
+ status = FlowStatus.INFEASIBLE
367
+
368
+ return MinCostFlowResult(
369
+ flow=flow,
370
+ cost=total_cost,
371
+ status=status,
372
+ iterations=iterations,
373
+ )
374
+
375
+
300
376
  def assignment_from_flow_solution(
301
377
  flow: NDArray[np.float64],
302
378
  edges: list[FlowEdge],
@@ -346,14 +422,21 @@ def assignment_from_flow_solution(
346
422
 
347
423
  def min_cost_assignment_via_flow(
348
424
  cost_matrix: NDArray[np.float64],
425
+ use_simplex: bool = True,
349
426
  ) -> Tuple[NDArray[np.intp], float]:
350
427
  """
351
428
  Solve 2D assignment problem via min-cost flow network.
352
429
 
430
+ Uses Dijkstra-optimized successive shortest paths (Phase 1B) by default.
431
+ Falls back to Bellman-Ford if needed.
432
+
353
433
  Parameters
354
434
  ----------
355
435
  cost_matrix : ndarray
356
436
  Cost matrix of shape (m, n).
437
+ use_simplex : bool, optional
438
+ Use Dijkstra-optimized algorithm (default True) or
439
+ Bellman-Ford based successive shortest paths (False).
357
440
 
358
441
  Returns
359
442
  -------
@@ -361,9 +444,19 @@ def min_cost_assignment_via_flow(
361
444
  Assignment array of shape (n_assignments, 2).
362
445
  total_cost : float
363
446
  Total assignment cost.
447
+
448
+ Notes
449
+ -----
450
+ Phase 1B: Dijkstra-based optimization provides O(K*E log V) vs
451
+ Bellman-Ford O(K*V*E), where K is number of shortest paths needed.
364
452
  """
365
453
  edges, supplies, _ = assignment_to_flow_network(cost_matrix)
366
- result = min_cost_flow_successive_shortest_paths(edges, supplies)
454
+
455
+ if use_simplex:
456
+ result = min_cost_flow_simplex(edges, supplies)
457
+ else:
458
+ result = min_cost_flow_successive_shortest_paths(edges, supplies)
459
+
367
460
  assignment, cost = assignment_from_flow_solution(
368
461
  result.flow, edges, cost_matrix.shape
369
462
  )