paramrf 0.37.4__tar.gz → 0.37.6__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 (278) hide show
  1. {paramrf-0.37.4 → paramrf-0.37.6}/AGENTS.md +0 -1
  2. {paramrf-0.37.4 → paramrf-0.37.6}/CLAUDE.md +0 -1
  3. {paramrf-0.37.4 → paramrf-0.37.6}/CONTEXT.md +70 -6
  4. {paramrf-0.37.4/paramrf.egg-info → paramrf-0.37.6}/PKG-INFO +2 -2
  5. paramrf-0.37.6/docs/adr/0008-shared-discrepancy.md +40 -0
  6. paramrf-0.37.6/docs/adr/0009-least-squares-map-fits.md +106 -0
  7. {paramrf-0.37.4 → paramrf-0.37.6/paramrf.egg-info}/PKG-INFO +2 -2
  8. {paramrf-0.37.4 → paramrf-0.37.6}/paramrf.egg-info/SOURCES.txt +7 -0
  9. {paramrf-0.37.4 → paramrf-0.37.6}/paramrf.egg-info/requires.txt +1 -1
  10. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/minimize.py +32 -2
  11. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/objectives/__init__.py +3 -1
  12. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/objectives/evaluators.py +287 -29
  13. paramrf-0.37.6/pmrf/objectives/problems.py +268 -0
  14. paramrf-0.37.6/pmrf/objectives/shared.py +278 -0
  15. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/objectives/terms.py +16 -1
  16. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/__init__.py +4 -1
  17. paramrf-0.37.6/pmrf/optimize/base.py +383 -0
  18. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/minimize.py +8 -1
  19. paramrf-0.37.6/pmrf/optimize/solvers/scipy.py +460 -0
  20. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/parameters/__init__.py +14 -1
  21. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/__init__.py +9 -1
  22. paramrf-0.37.6/pmrf/stats/shared_discrepancy.py +108 -0
  23. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/debug.py +43 -18
  24. {paramrf-0.37.4 → paramrf-0.37.6}/pyproject.toml +2 -2
  25. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_evaluators.py +88 -3
  26. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_fitting_minimize.py +52 -1
  27. paramrf-0.37.6/tests/test_least_squares.py +565 -0
  28. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_linearization.py +106 -10
  29. paramrf-0.37.6/tests/test_parameter_construction_cost.py +44 -0
  30. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_parameters_prior.py +3 -1
  31. paramrf-0.37.6/tests/test_shared_discrepancy.py +464 -0
  32. paramrf-0.37.6/tests/test_utils/test_debug.py +172 -0
  33. paramrf-0.37.4/pmrf/objectives/problems.py +0 -155
  34. paramrf-0.37.4/pmrf/optimize/base.py +0 -216
  35. paramrf-0.37.4/pmrf/optimize/solvers/scipy.py +0 -236
  36. paramrf-0.37.4/tests/test_utils/test_debug.py +0 -61
  37. {paramrf-0.37.4 → paramrf-0.37.6}/.github/workflows/docs.yml +0 -0
  38. {paramrf-0.37.4 → paramrf-0.37.6}/.github/workflows/draft-pdf.yml +0 -0
  39. {paramrf-0.37.4 → paramrf-0.37.6}/.github/workflows/publish.yml +0 -0
  40. {paramrf-0.37.4 → paramrf-0.37.6}/.github/workflows/tests.yml +0 -0
  41. {paramrf-0.37.4 → paramrf-0.37.6}/.gitignore +0 -0
  42. {paramrf-0.37.4 → paramrf-0.37.6}/CHANGELOG.md +0 -0
  43. {paramrf-0.37.4 → paramrf-0.37.6}/CITATION.cff +0 -0
  44. {paramrf-0.37.4 → paramrf-0.37.6}/CONTRIBUTING.md +0 -0
  45. {paramrf-0.37.4 → paramrf-0.37.6}/LICENSE +0 -0
  46. {paramrf-0.37.4 → paramrf-0.37.6}/NOTICE +0 -0
  47. {paramrf-0.37.4 → paramrf-0.37.6}/README.rst +0 -0
  48. {paramrf-0.37.4 → paramrf-0.37.6}/assets/logo.png +0 -0
  49. {paramrf-0.37.4 → paramrf-0.37.6}/docs/Makefile +0 -0
  50. {paramrf-0.37.4 → paramrf-0.37.6}/docs/_static/custom.css +0 -0
  51. {paramrf-0.37.4 → paramrf-0.37.6}/docs/_templates/autosummary/class.rst +0 -0
  52. {paramrf-0.37.4 → paramrf-0.37.6}/docs/_templates/autosummary/function.rst +0 -0
  53. {paramrf-0.37.4 → paramrf-0.37.6}/docs/_templates/autosummary/module.rst +0 -0
  54. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0001-line-modelling-architecture.md +0 -0
  55. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0002-parameter-api.md +0 -0
  56. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0003-derived-models.md +0 -0
  57. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0004-profiled-lines.md +0 -0
  58. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0005-priors-by-name.md +0 -0
  59. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0006-reference-impedance.md +0 -0
  60. {paramrf-0.37.4 → paramrf-0.37.6}/docs/adr/0007-edge-values.md +0 -0
  61. {paramrf-0.37.4 → paramrf-0.37.6}/docs/agents/domain.md +0 -0
  62. {paramrf-0.37.4 → paramrf-0.37.6}/docs/agents/issue-tracker.md +0 -0
  63. {paramrf-0.37.4 → paramrf-0.37.6}/docs/agents/triage-labels.md +0 -0
  64. {paramrf-0.37.4 → paramrf-0.37.6}/docs/api/index.rst +0 -0
  65. {paramrf-0.37.4 → paramrf-0.37.6}/docs/conf.py +0 -0
  66. {paramrf-0.37.4 → paramrf-0.37.6}/docs/core_concepts/core_primitives.rst +0 -0
  67. {paramrf-0.37.4 → paramrf-0.37.6}/docs/core_concepts/index.rst +0 -0
  68. {paramrf-0.37.4 → paramrf-0.37.6}/docs/core_concepts/jax_overview.rst +0 -0
  69. {paramrf-0.37.4 → paramrf-0.37.6}/docs/core_concepts/optimization_and_inference.rst +0 -0
  70. {paramrf-0.37.4 → paramrf-0.37.6}/docs/core_concepts/parameter_names.rst +0 -0
  71. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/cascading_and_terminating.rst +0 -0
  72. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/circuit_clc.png +0 -0
  73. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/circuit_models.rst +0 -0
  74. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/custom_models.rst +0 -0
  75. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/derivatives_and_sweeps.rst +0 -0
  76. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/discrepancy_prediction.rst +0 -0
  77. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/index.rst +0 -0
  78. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/model_optimization.rst +0 -0
  79. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/multiple_models_one_parameter_set.rst +0 -0
  80. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/parameter_naming_and_model_manipulation.rst +0 -0
  81. {paramrf-0.37.4 → paramrf-0.37.6}/docs/examples/shared_modules.rst +0 -0
  82. {paramrf-0.37.4 → paramrf-0.37.6}/docs/index.rst +0 -0
  83. {paramrf-0.37.4 → paramrf-0.37.6}/docs/license.rst +0 -0
  84. {paramrf-0.37.4 → paramrf-0.37.6}/docs/make.bat +0 -0
  85. {paramrf-0.37.4 → paramrf-0.37.6}/docs/research/conductor-loss-alternatives.md +0 -0
  86. {paramrf-0.37.4 → paramrf-0.37.6}/docs/research/holloway1994.pdf +0 -0
  87. {paramrf-0.37.4 → paramrf-0.37.6}/docs/research/microstrip-loss-conventions.md +0 -0
  88. {paramrf-0.37.4 → paramrf-0.37.6}/docs/research/precision-coax-microstrip-10-500mhz.md +0 -0
  89. {paramrf-0.37.4 → paramrf-0.37.6}/docs/skrf_comparison/index.rst +0 -0
  90. {paramrf-0.37.4 → paramrf-0.37.6}/docs/skrf_comparison/overview.rst +0 -0
  91. {paramrf-0.37.4 → paramrf-0.37.6}/docs/skrf_comparison/performance.rst +0 -0
  92. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/1_cable_fitting.ipynb +0 -0
  93. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/2_chip_inductor_fitting.ipynb +0 -0
  94. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/3_discrepancy_transfer.ipynb +0 -0
  95. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/data/CBN-1.5FT-SMSM.s2p +0 -0
  96. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/data/on-chip-inductor.s2p +0 -0
  97. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/index.rst +0 -0
  98. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/line_internal_discrepancy.py +0 -0
  99. {paramrf-0.37.4 → paramrf-0.37.6}/docs/tutorials/port_discrepancy.py +0 -0
  100. {paramrf-0.37.4 → paramrf-0.37.6}/paper/paper.bib +0 -0
  101. {paramrf-0.37.4 → paramrf-0.37.6}/paper/paper.md +0 -0
  102. {paramrf-0.37.4 → paramrf-0.37.6}/paper/rlc.png +0 -0
  103. {paramrf-0.37.4 → paramrf-0.37.6}/paramrf.egg-info/dependency_links.txt +0 -0
  104. {paramrf-0.37.4 → paramrf-0.37.6}/paramrf.egg-info/top_level.txt +0 -0
  105. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/__init__.py +0 -0
  106. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/_solver_view.py +0 -0
  107. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/__init__.py +0 -0
  108. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/result.py +0 -0
  109. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/routers.py +0 -0
  110. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/sample.py +0 -0
  111. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/fitting/targets.py +0 -0
  112. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/frequency.py +0 -0
  113. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/__init__.py +0 -0
  114. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/base.py +0 -0
  115. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/result.py +0 -0
  116. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/sample.py +0 -0
  117. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/solvers/__init__.py +0 -0
  118. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/solvers/blackjax.py +0 -0
  119. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/infer/solvers/polychord.py +0 -0
  120. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/__init__.py +0 -0
  121. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/conductor.py +0 -0
  122. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/dielectric.py +0 -0
  123. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/properties.py +0 -0
  124. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/roughness.py +0 -0
  125. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/substrate.py +0 -0
  126. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/materials/surface_impedance.py +0 -0
  127. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/__init__.py +0 -0
  128. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/aggregations.py +0 -0
  129. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/bessel.py +0 -0
  130. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/conversions.py +0 -0
  131. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/losses.py +0 -0
  132. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/math/misc.py +0 -0
  133. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/__init__.py +0 -0
  134. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/__init__.py +0 -0
  135. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/base.py +0 -0
  136. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/bridge.py +0 -0
  137. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/callable.py +0 -0
  138. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/delegated.py +0 -0
  139. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/derived.py +0 -0
  140. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/static.py +0 -0
  141. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/adapters/wrapped.py +0 -0
  142. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/base.py +0 -0
  143. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/__init__.py +0 -0
  144. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/ideal.py +0 -0
  145. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/__init__.py +0 -0
  146. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/base.py +0 -0
  147. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/coaxial.py +0 -0
  148. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/empirical.py +0 -0
  149. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/ideal.py +0 -0
  150. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/microstrip.py +0 -0
  151. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/nodal.py +0 -0
  152. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/nonuniform.py +0 -0
  153. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/planar.py +0 -0
  154. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/profiles.py +0 -0
  155. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lines/stripline.py +0 -0
  156. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/lumped.py +0 -0
  157. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/components/sections.py +0 -0
  158. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/__init__.py +0 -0
  159. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/__init__.py +0 -0
  160. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/cascade.py +0 -0
  161. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/__init__.py +0 -0
  162. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/base.py +0 -0
  163. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/circuit.py +0 -0
  164. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/solvers/__init__.py +0 -0
  165. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/solvers/nodal.py +0 -0
  166. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/circuit/solvers/scattering.py +0 -0
  167. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/interconnected/terminated.py +0 -0
  168. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/nodal.py +0 -0
  169. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/topological.py +0 -0
  170. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/composite/transformed.py +0 -0
  171. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/line_discrepancy.py +0 -0
  172. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/port_discrepancy.py +0 -0
  173. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/surrogates/__init__.py +0 -0
  174. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/surrogates/expansion.py +0 -0
  175. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/models/surrogates/rational.py +0 -0
  176. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/modules/__init__.py +0 -0
  177. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/modules/base.py +0 -0
  178. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/modules/wrapped.py +0 -0
  179. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/network_collection.py +0 -0
  180. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/objectives/losses.py +0 -0
  181. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/result.py +0 -0
  182. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/solvers/__init__.py +0 -0
  183. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/solvers/jaxopt.py +0 -0
  184. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/optimize/solvers/optimistix.py +0 -0
  185. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/parameters/constraints.py +0 -0
  186. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/rf/__init__.py +0 -0
  187. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/rf/cascade.py +0 -0
  188. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/rf/conversions.py +0 -0
  189. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/rf/mna.py +0 -0
  190. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/serialization.py +0 -0
  191. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/bijectors.py +0 -0
  192. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/covariance_kernels.py +0 -0
  193. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/discrepancy_models.py +0 -0
  194. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/distributions.py +0 -0
  195. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/likelihoods.py +0 -0
  196. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/linearization.py +0 -0
  197. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/stats/noise_models.py +0 -0
  198. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/types.py +0 -0
  199. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/__init__.py +0 -0
  200. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/array.py +0 -0
  201. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/network.py +0 -0
  202. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/random.py +0 -0
  203. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/rf.py +0 -0
  204. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/transforms.py +0 -0
  205. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/tree.py +0 -0
  206. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/utils/type.py +0 -0
  207. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/viz/__init__.py +0 -0
  208. {paramrf-0.37.4 → paramrf-0.37.6}/pmrf/viz/plots.py +0 -0
  209. {paramrf-0.37.4 → paramrf-0.37.6}/scripts/benchmark_gp_marginal_likelihood.py +0 -0
  210. {paramrf-0.37.4 → paramrf-0.37.6}/scripts/install-test-deps.sh +0 -0
  211. {paramrf-0.37.4 → paramrf-0.37.6}/setup.cfg +0 -0
  212. {paramrf-0.37.4 → paramrf-0.37.6}/tests/__init__.py +0 -0
  213. {paramrf-0.37.4 → paramrf-0.37.6}/tests/_jit.py +0 -0
  214. {paramrf-0.37.4 → paramrf-0.37.6}/tests/conftest.py +0 -0
  215. {paramrf-0.37.4 → paramrf-0.37.6}/tests/data/10m_cable.s2p +0 -0
  216. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_autodiff.py +0 -0
  217. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_box_space_solving.py +0 -0
  218. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_conversions.py +0 -0
  219. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_covariance_kernels.py +0 -0
  220. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_dc_limits.py +0 -0
  221. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_discrepancy_models.py +0 -0
  222. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_fitting_routers.py +0 -0
  223. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_fitting_sample.py +0 -0
  224. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_fitting_targets.py +0 -0
  225. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_frequency.py +0 -0
  226. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_grouped_exports.py +0 -0
  227. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_infer_base.py +0 -0
  228. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_infer_sample.py +0 -0
  229. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_line_internal_discrepancy_example.py +0 -0
  230. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_map_priors.py +0 -0
  231. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_materials/test_conductor.py +0 -0
  232. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_materials/test_dielectric.py +0 -0
  233. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_materials/test_serialization.py +0 -0
  234. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_materials/test_substrate.py +0 -0
  235. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_materials/test_surface_impedance.py +0 -0
  236. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_math/test_bessel.py +0 -0
  237. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_model.py +0 -0
  238. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_adapters.py +0 -0
  239. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_cascade.py +0 -0
  240. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_native_z0.py +0 -0
  241. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_nodal.py +0 -0
  242. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_port_order.py +0 -0
  243. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_scattering.py +0 -0
  244. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_shorted_ports.py +0 -0
  245. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_skrf_port_names.py +0 -0
  246. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_circuit_z0.py +0 -0
  247. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_current_distribution.py +0 -0
  248. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_derived.py +0 -0
  249. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_edge_values.py +0 -0
  250. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_interconnected.py +0 -0
  251. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_line_discrepancy.py +0 -0
  252. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_lines.py +0 -0
  253. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_lines_skrf_matrix.py +0 -0
  254. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_lumped.py +0 -0
  255. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_nodal.py +0 -0
  256. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_port_discrepancy.py +0 -0
  257. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_profiles.py +0 -0
  258. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_rational.py +0 -0
  259. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_repeated_cascade.py +0 -0
  260. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_sections.py +0 -0
  261. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_transformed.py +0 -0
  262. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_models/test_transformers.py +0 -0
  263. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_module.py +0 -0
  264. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_naming.py +0 -0
  265. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_optimize_base.py +0 -0
  266. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_optimize_minimize.py +0 -0
  267. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_parameters.py +0 -0
  268. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_parameters_by_name.py +0 -0
  269. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_parameters_joint_prior.py +0 -0
  270. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_parameters_validity.py +0 -0
  271. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_port_discrepancy_example.py +0 -0
  272. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_raw_space_solving.py +0 -0
  273. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_serialization.py +0 -0
  274. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_structural_updates.py +0 -0
  275. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_terms.py +0 -0
  276. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_transforms.py +0 -0
  277. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_utils/test_compress.py +0 -0
  278. {paramrf-0.37.4 → paramrf-0.37.6}/tests/test_utils/test_tree.py +0 -0
@@ -27,7 +27,6 @@ there are none.
27
27
 
28
28
  ```bash
29
29
  .venv/bin/python -m pytest tests/test_x.py # the tests covering a change, while working
30
- .venv/bin/python -m pytest -n 4 # local test command: full suite, once before committing
31
30
  .venv/bin/python -c "import pmrf" # import smoke check
32
31
  ```
33
32
 
@@ -27,7 +27,6 @@ there are none.
27
27
 
28
28
  ```bash
29
29
  .venv/bin/python -m pytest tests/test_x.py # the tests covering a change, while working
30
- .venv/bin/python -m pytest -n 4 # local test command: full suite, once before committing
31
30
  .venv/bin/python -c "import pmrf" # import smoke check
32
31
  ```
33
32
 
@@ -184,9 +184,10 @@ noise. `pmrf.objectives.MarginalLogLikelihood` scores it; see
184
184
  The space in which probability is defined: the prediction after the event
185
185
  transform, with frequency as the last (event) axis. Every other axis is a batch
186
186
  axis. One entry of that batch, for example the real part of S21, is an **event
187
- block**. Blocks are independent: a kernel chooses the covariance *within* each
188
- block (`AutoCrossKernel` routes by block, `SharedIndependentKernel` shares
189
- hyperparameters across blocks) and never couples two blocks.
187
+ block**. Under a `GaussianProcess` discrepancy, blocks are independent: a kernel
188
+ chooses the covariance *within* each block (`AutoCrossKernel` routes by block,
189
+ `SharedIndependentKernel` shares hyperparameters across blocks) and never couples
190
+ two blocks. A **shared discrepancy** couples blocks, and datasets.
190
191
 
191
192
  *Avoid:* "output" or "task" for a block; "cross-covariance" for the kernel an
192
193
  `AutoCrossKernel` gives a transmission block.
@@ -194,8 +195,40 @@ hyperparameters across blocks) and never couples two blocks.
194
195
  ### Discrepancy
195
196
 
196
197
  $\delta$, the systematic misfit between model and reality, as opposed to noise
197
- $\varepsilon$. Either deterministic or a `GaussianProcess` over each event block.
198
- It is on the observable unless it is a port or internal discrepancy.
198
+ $\varepsilon$. Either deterministic, a `GaussianProcess` over each event block, or
199
+ a shared discrepancy. It is on the observable unless it is a port or internal
200
+ discrepancy.
201
+
202
+ ### Shared latent
203
+
204
+ A function of frequency with a Gaussian-process prior, common to several event blocks
205
+ or several datasets: for example a VNA's residual directivity, which is the same for
206
+ every device measured with one calibration. It has one or more rows (two for a
207
+ complex function: Re and Im), each an independent draw from its kernel.
208
+
209
+ *Avoid:* "task", "output" (those are event blocks); "error term" (one application's name
210
+ for it); "coregionalisation" in user-facing text.
211
+
212
+ ### Mixing
213
+
214
+ The linear map, at each frequency, from a shared latent's rows to one dataset's event
215
+ blocks. It may depend on that dataset's prediction: multiplying a complex latent by the
216
+ predicted reflection coefficient is a mixing. A mixing may carry parameters.
217
+
218
+ ### Shared discrepancy
219
+
220
+ The discrepancy formed by mixing shared latents:
221
+ $\delta_l(f) = \sum_j M_{lj}(f)\, g_j(f)$ for dataset $l$, with per-dataset noise on
222
+ top. Because the latents are common, it couples the datasets and the event blocks it
223
+ mixes into. `pmrf.objectives.SharedMarginalLogLikelihood` scores it.
224
+
225
+ ### Latent prediction
226
+
227
+ The joint distribution of the shared latents at new frequencies, conditioned on the
228
+ residuals of every dataset, excluding noise. It is what transfers to a new dataset that
229
+ shares the latents, through that dataset's mixing.
230
+
231
+ *Avoid:* "discrepancy prediction" for this (that is per dataset, in event space).
199
232
 
200
233
  ### Residual
201
234
 
@@ -236,6 +269,34 @@ together, from a linearisation: unlike a discrepancy prediction, it carries the
236
269
  parameters' uncertainty into $\delta$ and the cross-covariance between them. It is
237
270
  the form in which one fit's posterior becomes the next fit's joint prior.
238
271
 
272
+ ### Hyperparameter
273
+
274
+ A free parameter owned by a term rather than by the model, such as white noise or a
275
+ kernel's length scale. The model parameters are the free parameters of
276
+ `problem.model`; the hyperparameters are the rest (ADR-0009).
277
+
278
+ ### Whitened residual
279
+
280
+ A term's residual scaled so that half its squared norm is the term's negative log
281
+ likelihood, up to terms constant in the model parameters, with the hyperparameters
282
+ held: $L^{-1} r$ per event block for a `MarginalLogLikelihood`, with
283
+ $\Sigma_D = K + \Sigma_n = L L^\top$. Its Jacobian is the whitened Jacobian of a
284
+ linearisation (ADR-0009).
285
+
286
+ ### Prior residual
287
+
288
+ A free parameter's contribution to a least-squares fit from its prior: half its
289
+ squared norm is the negative log prior, up to a constant. $(\theta - \mu)/\sigma$ for a
290
+ normal or truncated normal prior, the Cholesky-whitened $\theta - \mu$ for a joint
291
+ normal prior, and nothing for a uniform prior, whose bounds are the box edges instead.
292
+ It is computed from the distribution, not read from raw space (ADR-0009).
293
+
294
+ ### Hyperparameter step
295
+
296
+ In an alternating MAP fit, the scalar minimisation of the full negative log posterior
297
+ over the hyperparameters with the model parameters held. It takes the
298
+ $\tfrac{1}{2}\ln|\Sigma_D|$ term, which a least-squares solve cannot (ADR-0009).
299
+
239
300
  ### Port discrepancy
240
301
 
241
302
  A discrepancy embedded at a component's ports, on its S-parameters rather than on
@@ -309,4 +370,7 @@ method, a public function or a value space. Read
309
370
  `docs/adr/0005-priors-by-name.md` before changing how priors are attached or
310
371
  scored, and `docs/adr/0007-edge-values.md` before changing how a
311
372
  circuit solver produces S, how bounds are validated, or which space a solver
312
- moves through.
373
+ moves through. Read `docs/adr/0008-shared-discrepancy.md` before coupling event
374
+ blocks or datasets in a discrepancy, and `docs/adr/0009-least-squares-map-fits.md`
375
+ before changing how a least-squares minimiser builds its residual or treats
376
+ hyperparameters.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramrf
3
- Version: 0.37.4
3
+ Version: 0.37.6
4
4
  Summary: Parametric radio frequency modeling
5
5
  Author-email: Gary Allen <gvcallen@gmail.com>
6
6
  Project-URL: homepage, https://github.com/gvcallen/paramrf
7
7
  Description-Content-Type: text/x-rst
8
8
  License-File: LICENSE
9
9
  License-File: NOTICE
10
- Requires-Dist: parax>=0.11.6
10
+ Requires-Dist: parax>=0.11.7
11
11
  Requires-Dist: threadpoolctl
12
12
  Requires-Dist: eqxpress
13
13
  Requires-Dist: jax
@@ -0,0 +1,40 @@
1
+ # Shared discrepancy is a joint evaluator over per-dataset likelihoods
2
+
3
+ A discrepancy whose latent functions are shared across datasets (or across event blocks
4
+ of one dataset) makes those datasets statistically dependent, so their joint likelihood
5
+ is not a sum of per-dataset terms. We add a new evaluator,
6
+ `SharedMarginalLogLikelihood`, that takes several ordinary `MarginalLogLikelihood`s
7
+ (each with no discrepancy of its own) plus a tuple of `SharedLatent`s, and returns one
8
+ joint log-likelihood. It goes into `SummedTerms` as a single term. Each `SharedLatent`
9
+ is a covariance kernel paired with a **mixing**: a function of the dataset's
10
+ event-space prediction and frequency that returns, per frequency, a real matrix from
11
+ the latent's rows to the dataset's event blocks. The joint covariance is low rank plus
12
+ diagonal and is solved by Woodbury in the latent dimension, never densely.
13
+
14
+ ## Considered options
15
+
16
+ - **A shared object inside several `MarginalLogLikelihood` terms, marginalised jointly by
17
+ `SummedTerms`.** Rejected: `SummedTerms` would have to detect sharing and stop being a
18
+ sum, and the joint maths would be spread across classes that should not know about
19
+ each other.
20
+ - **Extend `GaussianProcess` and its kernels to couple event blocks** (as in the
21
+ correlated-GP note and the routing idea in #250). Rejected: a `GaussianProcess` is a
22
+ discrepancy for one dataset, and its kernels cannot see the prediction, which
23
+ multiplicative error (for example a VNA's tracking error, $e_t \Gamma$) needs.
24
+ - **An error-box model component with GP-distributed error terms.** This is the exact
25
+ bilinear form, but its marginal is not Gaussian. It is a separate, later feature.
26
+
27
+ ## Consequences
28
+
29
+ - `MarginalLogLikelihood` exposes its event-space residual, noise variance and
30
+ conditional-transform log-determinant, so the joint evaluator reuses all per-dataset
31
+ plumbing (predictor, observation, likelihood, event transform) without copying it.
32
+ - A latent holds a kernel, not a `GaussianProcess`. Every existing kernel is reusable.
33
+ - Mixings act in event space. Helpers that multiply by the prediction assume the
34
+ default Re/Im event layout and say so.
35
+ - With a prediction-dependent mixing, the covariance depends on the model parameters;
36
+ gradients flow through it.
37
+ - A `MarginalLogLikelihood` with a `GaussianProcess` is mathematically the one-dataset,
38
+ identity-mixing case. Both stay: the existing class is the fast independent-block
39
+ path. If the two ever duplicate maths rather than share plumbing, merge them into one
40
+ evaluator with the independent path as an internal optimisation.
@@ -0,0 +1,106 @@
1
+ # ADR-0009: MAP fits are bounded least squares, alternating with a hyperparameter step
2
+
3
+ Status: accepted (2026-10)
4
+
5
+ ## Context
6
+
7
+ Physical line models often have parameters that are each identifiable but jointly
8
+ near-degenerate: the loss is a long, narrow valley. On a synthetic `MicrostripLine` fit
9
+ (10-500 MHz, `w`, `h`, `ep_r`, `tand`, `sigma` and `length` free, noise 1e-5, Jacobian
10
+ condition number about 4e5 in box space), starting from a perturbed point:
11
+
12
+ | Method | Outcome |
13
+ |---|---|
14
+ | `ScipyMinimize` L-BFGS-B (default) | Reports success at a wrong point |
15
+ | `ScipyMinimize` trust-constr (BFGS) | Not converged in 3000 iterations |
16
+ | trust-constr, exact JAX Hessian | Not converged in 3000 iterations, about 20x slower |
17
+ | trust-constr, Gauss-Newton Hessian | Not converged in 3000 iterations |
18
+ | trust-exact, Levenberg-Marquardt (unbounded) | Leave the box and fail |
19
+ | Optimistix Levenberg-Marquardt, Dogleg, Gauss-Newton (raw space) | Stall on the bounds, where the raw Jacobian vanishes |
20
+ | SciPy `least_squares`, `'trf'`, box space | Recovers all six true values |
21
+
22
+ The exact Hessian adds the residual-weighted second derivative of the model, the term a
23
+ linearisation drops. Far from the solution it hurts rather than helps.
24
+
25
+ Under a Gaussian likelihood with fixed noise and discrepancy hyperparameters, the negative
26
+ log posterior is half the squared norm of a residual vector, up to a constant, whenever
27
+ each prior is Gaussian, truncated Gaussian or uniform. Noise and kernel hyperparameters
28
+ are usually fitted too, and they enter through $\tfrac{1}{2}\ln|\Sigma_D|$, which is not a
29
+ square.
30
+
31
+ ## Decision
32
+
33
+ ### A least-squares minimiser over box space
34
+
35
+ `pmrf.optimize.ScipyLeastSquares` wraps `scipy.optimize.least_squares` with `'trf'`. Like
36
+ any minimiser that honours bounds, it searches box space and is given the box's edges
37
+ (ADR-0007). It minimises half the squared norm of a residual vector, not a scalar.
38
+
39
+ ### The residual vector
40
+
41
+ The vector stacks the **whitened residual** of each term and the **prior residual** of each
42
+ free parameter.
43
+
44
+ - **Whitened residual.** For a `MarginalLogLikelihood`, $L^{-1} r$ per event block, with
45
+ $L$ the lower Cholesky factor of $\Sigma_D = K + \Sigma_n$: the same factor
46
+ `linearize` uses. For a `TargetLoss` with `MSELoss`, the prediction error scaled so
47
+ that half its squared norm is the loss.
48
+ - **Prior residual.** Computed from the distribution, in the space it is over. It is not
49
+ the raw value, since truncation makes the raw map nonlinear.
50
+
51
+ | Prior | Prior residual | Bounds |
52
+ |---|---|---|
53
+ | `Normal` | $(\theta - \mu)/\sigma$ | none |
54
+ | `TruncatedNormal`, including a `Normal` truncated to a validity | $(\theta - \mu)/\sigma$ | the truncation |
55
+ | Joint multivariate normal, including `truncate='unnormalised'` | $L_0^{-1}(\theta - \mu)$, with $\Sigma_0 = L_0 L_0^\top$ | each parameter's validity |
56
+ | `Uniform`, or no prior | none | the parameter's bounds |
57
+
58
+ A truncation normaliser is constant in $\theta$, so it does not move the MAP.
59
+
60
+ ### Alternating with a hyperparameter step
61
+
62
+ The level above the minimiser splits the free parameters. The model parameters are the
63
+ free parameters of `problem.model`. The **hyperparameters** are the free parameters the
64
+ terms own, such as white noise and kernel hyperparameters. `run_minimizer` hands the
65
+ minimiser both groups: a residual function of the model parameters given the
66
+ hyperparameters, and the full scalar objective of the hyperparameters given the model
67
+ parameters. The minimiser knows nothing about noise or kernels.
68
+
69
+ Each round is a least-squares solve over the model parameters, then a **hyperparameter
70
+ step**: a scalar minimisation of the full negative log posterior over the hyperparameters
71
+ with the model parameters held, by `hyper_minimizer` (default `ScipyMinimize()`). The fit
72
+ stops when a round no longer decreases the full objective. With no free hyperparameters
73
+ it is a single least-squares solve.
74
+
75
+ ### Not yet supported
76
+
77
+ Each of these raises an error saying it is not yet supported:
78
+
79
+ - noise given as a callable of the prediction, since $\Sigma_D$ then depends on the
80
+ model parameters;
81
+ - a mixing that depends on the prediction, for the same reason;
82
+ - orthogonal discrepancy without a fixed reference basis;
83
+ - priors other than those in the table, such as a prior over raw space carried to
84
+ declared space with a change-of-variables term;
85
+ - `GibbsMarginalLogLikelihood`, losses other than `MSELoss`, and any term without a
86
+ whitened residual.
87
+
88
+ ## Considered options
89
+
90
+ - **Restore the exact Hessian in `ScipyMinimize`.** Rejected as the fix: it did not
91
+ converge on the degenerate fit and is slow to compile. It may still be added for other
92
+ reasons.
93
+ - **Optimistix least-squares solvers.** They keep the fit in JAX, but take no bounds, and
94
+ in raw space they stall on the bounds. Rejected.
95
+ - **One least-squares solve over model parameters and hyperparameters together.** The
96
+ log-determinant is not a square; writing it as one gives a residual with a singular
97
+ derivative. Rejected.
98
+
99
+ ## Consequences
100
+
101
+ - At the MAP, the stacked whitened Jacobian and prior square root of the last
102
+ least-squares solve are the $A$ of `posterior_covariance_factor`. The fit and its
103
+ linearisation share one approximation.
104
+ - `ScipyMinimize`'s commented-out Hessian path is removed.
105
+ - Shared discrepancy is supported once its whitened residual covers the joint covariance
106
+ across datasets, for mixings that do not depend on the prediction.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramrf
3
- Version: 0.37.4
3
+ Version: 0.37.6
4
4
  Summary: Parametric radio frequency modeling
5
5
  Author-email: Gary Allen <gvcallen@gmail.com>
6
6
  Project-URL: homepage, https://github.com/gvcallen/paramrf
7
7
  Description-Content-Type: text/x-rst
8
8
  License-File: LICENSE
9
9
  License-File: NOTICE
10
- Requires-Dist: parax>=0.11.6
10
+ Requires-Dist: parax>=0.11.7
11
11
  Requires-Dist: threadpoolctl
12
12
  Requires-Dist: eqxpress
13
13
  Requires-Dist: jax
@@ -30,6 +30,8 @@ docs/adr/0004-profiled-lines.md
30
30
  docs/adr/0005-priors-by-name.md
31
31
  docs/adr/0006-reference-impedance.md
32
32
  docs/adr/0007-edge-values.md
33
+ docs/adr/0008-shared-discrepancy.md
34
+ docs/adr/0009-least-squares-map-fits.md
33
35
  docs/agents/domain.md
34
36
  docs/agents/issue-tracker.md
35
37
  docs/agents/triage-labels.md
@@ -155,6 +157,7 @@ pmrf/objectives/__init__.py
155
157
  pmrf/objectives/evaluators.py
156
158
  pmrf/objectives/losses.py
157
159
  pmrf/objectives/problems.py
160
+ pmrf/objectives/shared.py
158
161
  pmrf/objectives/terms.py
159
162
  pmrf/optimize/__init__.py
160
163
  pmrf/optimize/base.py
@@ -178,6 +181,7 @@ pmrf/stats/distributions.py
178
181
  pmrf/stats/likelihoods.py
179
182
  pmrf/stats/linearization.py
180
183
  pmrf/stats/noise_models.py
184
+ pmrf/stats/shared_discrepancy.py
181
185
  pmrf/utils/__init__.py
182
186
  pmrf/utils/array.py
183
187
  pmrf/utils/debug.py
@@ -209,6 +213,7 @@ tests/test_frequency.py
209
213
  tests/test_grouped_exports.py
210
214
  tests/test_infer_base.py
211
215
  tests/test_infer_sample.py
216
+ tests/test_least_squares.py
212
217
  tests/test_line_internal_discrepancy_example.py
213
218
  tests/test_linearization.py
214
219
  tests/test_map_priors.py
@@ -217,6 +222,7 @@ tests/test_module.py
217
222
  tests/test_naming.py
218
223
  tests/test_optimize_base.py
219
224
  tests/test_optimize_minimize.py
225
+ tests/test_parameter_construction_cost.py
220
226
  tests/test_parameters.py
221
227
  tests/test_parameters_by_name.py
222
228
  tests/test_parameters_joint_prior.py
@@ -225,6 +231,7 @@ tests/test_parameters_validity.py
225
231
  tests/test_port_discrepancy_example.py
226
232
  tests/test_raw_space_solving.py
227
233
  tests/test_serialization.py
234
+ tests/test_shared_discrepancy.py
228
235
  tests/test_structural_updates.py
229
236
  tests/test_terms.py
230
237
  tests/test_transforms.py
@@ -1,4 +1,4 @@
1
- parax>=0.11.6
1
+ parax>=0.11.7
2
2
  threadpoolctl
3
3
  eqxpress
4
4
  jax
@@ -40,6 +40,8 @@ def fit_minimize(
40
40
  noise: Param | Callable[[jnp.ndarray], jnp.ndarray] = None,
41
41
  discrepancy: Callable[[jnp.ndarray, jnp.ndarray], dist.AbstractDistribution] | None = None,
42
42
  temperature: float = None,
43
+ use_orthogonal_discrepancy: bool = False,
44
+ orthogonal_rcond: float | None = None,
43
45
  **kwargs,
44
46
  ) -> FitResult[PyTreeT]:
45
47
  """
@@ -61,6 +63,14 @@ def fit_minimize(
61
63
  solver : AbstractMinimizer, optional
62
64
  The optimizer to use.
63
65
  See :mod:`pmrf.optimize` for available solvers.
66
+ :class:`pmrf.optimize.ScipyLeastSquares` suits fits whose parameters are
67
+ jointly near-degenerate. It supports a frequentist fit with
68
+ :class:`pmrf.objectives.losses.MSELoss`, and a bayesian fit with a
69
+ :class:`pmrf.stats.likelihoods.GaussianLikelihood`, fitting a free noise and a
70
+ Gaussian-process discrepancy's hyperparameters by alternating with a
71
+ hyperparameter step. Noise given as a callable of the prediction, orthogonal
72
+ discrepancy without a fixed reference basis, and priors on the model other than
73
+ normal, truncated normal and uniform are not yet supported.
64
74
  features : str | list[str] | Callable[[PyTree, Frequency], jnp.ndarray], default='s'
65
75
  The RF features to fit.
66
76
  Can either be function, a callable PyTree with optional parameters, or a string,
@@ -114,6 +124,12 @@ def fit_minimize(
114
124
  The temperature value for generalized Bayesian optimization.
115
125
  Only allowed if `inference` is 'bayesian' and `loss` is not None.
116
126
  Defaults to 1.0 internally.
127
+ use_orthogonal_discrepancy : bool, default=False
128
+ Fix the discrepancy's tangent basis at the initial model for each dataset.
129
+ Requires a discrepancy model.
130
+ orthogonal_rcond : float, optional
131
+ Relative cutoff for the tangent basis singular values. Required when
132
+ enabling orthogonal discrepancy.
117
133
  **kwargs : dict
118
134
  Additional keyword arguments passed to :func:`pmrf.optimize.minimize`
119
135
  and then underlying solver.
@@ -139,6 +155,8 @@ def fit_minimize(
139
155
  raise ValueError("Only one of either `loss` or `likelihood` can be past to `fit_minimize`")
140
156
  if discrepancy is not None and not (likelihood is not None or inference == 'bayesian'):
141
157
  raise ValueError("Discrepancy models can only be passed if `likelihood` is passed or `inference` is 'bayesian'`")
158
+ if use_orthogonal_discrepancy and discrepancy is None:
159
+ raise ValueError("`use_orthogonal_discrepancy=True` requires a discrepancy model")
142
160
 
143
161
  # Resolve data and features
144
162
  datasets = resolve_datasets(features, data, frequency)
@@ -161,10 +179,22 @@ def fit_minimize(
161
179
  evaluator = TargetLoss(predictor=dataset.predictor, target=dataset.target, loss=loss)
162
180
  else:
163
181
  if likelihood is not None:
164
- mll = MarginalLogLikelihood(predictor=dataset.predictor, observed=dataset.target, likelihood=likelihood, discrepancy=discrepancy)
182
+ mll = MarginalLogLikelihood(
183
+ predictor=dataset.predictor, observed=dataset.target, likelihood=likelihood,
184
+ discrepancy=discrepancy,
185
+ use_orthogonal_discrepancy=use_orthogonal_discrepancy,
186
+ orthogonal_rcond=orthogonal_rcond,
187
+ )
165
188
  else:
166
189
  temperature = temperature if temperature is not None else 1.0
167
- mll = GibbsMarginalLogLikelihood(predictor=dataset.predictor, observed=dataset.target, loss=loss, discrepancy=discrepancy, temperature=temperature)
190
+ mll = GibbsMarginalLogLikelihood(
191
+ predictor=dataset.predictor, observed=dataset.target, loss=loss,
192
+ discrepancy=discrepancy, temperature=temperature,
193
+ use_orthogonal_discrepancy=use_orthogonal_discrepancy,
194
+ orthogonal_rcond=orthogonal_rcond,
195
+ )
196
+ if use_orthogonal_discrepancy:
197
+ mll = mll.with_orthogonal_reference(model, dataset.frequency)
168
198
  evaluator = Negated(mll)
169
199
  objective.append((evaluator, dataset.frequency))
170
200
 
@@ -31,6 +31,7 @@ if TYPE_CHECKING:
31
31
  SummedTerms as SummedTerms,
32
32
  problem_terms as problem_terms,
33
33
  )
34
+ from .shared import SharedMarginalLogLikelihood as SharedMarginalLogLikelihood
34
35
  from .terms import (
35
36
  AbstractTerm as AbstractTerm,
36
37
  BoundEvaluator as BoundEvaluator,
@@ -59,6 +60,7 @@ _EXPORTS = {
59
60
  'Negated': 'evaluators',
60
61
  'PriorPenalized': 'problems',
61
62
  'RMSELoss': 'losses',
63
+ 'SharedMarginalLogLikelihood': 'shared',
62
64
  'SummedTerms': 'problems',
63
65
  'TargetLoss': 'evaluators',
64
66
  'TermFn': 'terms',
@@ -66,7 +68,7 @@ _EXPORTS = {
66
68
  'as_terms': 'terms',
67
69
  'problem_terms': 'problems',
68
70
  }
69
- _MODULES = {'evaluators', 'losses', 'problems', 'terms'}
71
+ _MODULES = {'evaluators', 'losses', 'problems', 'shared', 'terms'}
70
72
 
71
73
  def __getattr__(name):
72
74
  if name in _MODULES: