paramrf 0.35.4__tar.gz → 0.36.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 (251) hide show
  1. {paramrf-0.35.4 → paramrf-0.36.0}/.github/workflows/docs.yml +1 -1
  2. paramrf-0.36.0/.github/workflows/tests.yml +62 -0
  3. {paramrf-0.35.4 → paramrf-0.36.0}/.gitignore +3 -0
  4. paramrf-0.36.0/AGENTS.md +90 -0
  5. paramrf-0.36.0/CLAUDE.md +90 -0
  6. {paramrf-0.35.4 → paramrf-0.36.0}/CONTEXT.md +21 -4
  7. {paramrf-0.35.4 → paramrf-0.36.0}/CONTRIBUTING.md +1 -1
  8. {paramrf-0.35.4/paramrf.egg-info → paramrf-0.36.0}/PKG-INFO +6 -10
  9. {paramrf-0.35.4 → paramrf-0.36.0}/README.rst +1 -7
  10. {paramrf-0.35.4 → paramrf-0.36.0}/docs/adr/0002-parameter-api.md +6 -6
  11. paramrf-0.36.0/docs/adr/0005-priors-by-name.md +162 -0
  12. paramrf-0.36.0/docs/adr/0006-reference-impedance.md +119 -0
  13. {paramrf-0.35.4 → paramrf-0.36.0}/docs/api/index.rst +1 -1
  14. {paramrf-0.35.4 → paramrf-0.36.0}/docs/core_concepts/parameter_names.rst +15 -15
  15. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/derivatives_and_sweeps.rst +1 -1
  16. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/model_optimization.rst +1 -1
  17. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/parameter_naming_and_model_manipulation.rst +3 -3
  18. paramrf-0.36.0/docs/examples/shared_substrates.rst +50 -0
  19. {paramrf-0.35.4 → paramrf-0.36.0}/docs/tutorials/1_cable_fitting.ipynb +1 -1
  20. {paramrf-0.35.4 → paramrf-0.36.0}/docs/tutorials/2_chip_inductor_fitting.ipynb +1 -1
  21. {paramrf-0.35.4 → paramrf-0.36.0/paramrf.egg-info}/PKG-INFO +6 -10
  22. {paramrf-0.35.4 → paramrf-0.36.0}/paramrf.egg-info/SOURCES.txt +9 -1
  23. {paramrf-0.35.4 → paramrf-0.36.0}/paramrf.egg-info/requires.txt +4 -2
  24. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/__init__.py +4 -2
  25. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/_solver_view.py +4 -4
  26. paramrf-0.36.0/pmrf/bijectors.py +47 -0
  27. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/discrepancy_models.py +1 -1
  28. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/distributions.py +17 -30
  29. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/evaluators.py +4 -4
  30. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/minimize.py +1 -1
  31. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/sample.py +1 -1
  32. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/base.py +154 -18
  33. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/likelihoods.py +1 -1
  34. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/__init__.py +1 -1
  35. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/base.py +118 -70
  36. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/ideal.py +14 -4
  37. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/cascade.py +15 -18
  38. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/circuit.py +45 -14
  39. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/modules/__init__.py +1 -4
  40. paramrf-0.36.0/pmrf/modules/wrapped.py +73 -0
  41. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/base.py +1 -1
  42. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/parameters.py +822 -123
  43. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/rf/cascade.py +37 -24
  44. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/transforms.py +2 -2
  45. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/tree.py +0 -12
  46. {paramrf-0.35.4 → paramrf-0.36.0}/pyproject.toml +5 -3
  47. {paramrf-0.35.4 → paramrf-0.36.0}/scripts/install-test-deps.sh +0 -2
  48. {paramrf-0.35.4 → paramrf-0.36.0}/tests/conftest.py +9 -0
  49. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_evaluators.py +2 -5
  50. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_fitting_sample.py +0 -10
  51. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_fitting_targets.py +88 -105
  52. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_infer_base.py +0 -3
  53. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_infer_sample.py +0 -3
  54. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_map_priors.py +2 -10
  55. paramrf-0.36.0/tests/test_models/test_cascade.py +190 -0
  56. paramrf-0.36.0/tests/test_models/test_circuit_native_z0.py +239 -0
  57. paramrf-0.36.0/tests/test_models/test_circuit_skrf_port_names.py +69 -0
  58. paramrf-0.36.0/tests/test_models/test_circuit_z0.py +139 -0
  59. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_derived.py +19 -11
  60. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_module.py +2 -15
  61. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_naming.py +13 -13
  62. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_optimize_base.py +2 -2
  63. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_parameters.py +4 -4
  64. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_parameters_by_name.py +23 -23
  65. paramrf-0.36.0/tests/test_parameters_joint_prior.py +686 -0
  66. paramrf-0.36.0/tests/test_parameters_prior.py +222 -0
  67. paramrf-0.36.0/tests/test_parameters_validity.py +225 -0
  68. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_raw_space_solving.py +55 -36
  69. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_structural_updates.py +11 -15
  70. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_transforms.py +8 -8
  71. paramrf-0.35.4/.github/workflows/tests.yml +0 -34
  72. paramrf-0.35.4/AGENTS.md +0 -89
  73. paramrf-0.35.4/CLAUDE.md +0 -89
  74. paramrf-0.35.4/docs/examples/shared_substrates.rst +0 -84
  75. paramrf-0.35.4/pmrf/bijectors.py +0 -70
  76. paramrf-0.35.4/pmrf/modules/wrapped.py +0 -143
  77. paramrf-0.35.4/tests/_dependency_checks.py +0 -22
  78. {paramrf-0.35.4 → paramrf-0.36.0}/.github/workflows/draft-pdf.yml +0 -0
  79. {paramrf-0.35.4 → paramrf-0.36.0}/.github/workflows/publish.yml +0 -0
  80. {paramrf-0.35.4 → paramrf-0.36.0}/CHANGELOG.md +0 -0
  81. {paramrf-0.35.4 → paramrf-0.36.0}/CITATION.cff +0 -0
  82. {paramrf-0.35.4 → paramrf-0.36.0}/LICENSE +0 -0
  83. {paramrf-0.35.4 → paramrf-0.36.0}/NOTICE +0 -0
  84. {paramrf-0.35.4 → paramrf-0.36.0}/assets/logo.png +0 -0
  85. {paramrf-0.35.4 → paramrf-0.36.0}/docs/Makefile +0 -0
  86. {paramrf-0.35.4 → paramrf-0.36.0}/docs/_static/custom.css +0 -0
  87. {paramrf-0.35.4 → paramrf-0.36.0}/docs/_templates/autosummary/class.rst +0 -0
  88. {paramrf-0.35.4 → paramrf-0.36.0}/docs/_templates/autosummary/function.rst +0 -0
  89. {paramrf-0.35.4 → paramrf-0.36.0}/docs/_templates/autosummary/module.rst +0 -0
  90. {paramrf-0.35.4 → paramrf-0.36.0}/docs/adr/0001-line-modelling-architecture.md +0 -0
  91. {paramrf-0.35.4 → paramrf-0.36.0}/docs/adr/0003-derived-models.md +0 -0
  92. {paramrf-0.35.4 → paramrf-0.36.0}/docs/adr/0004-profiled-lines.md +0 -0
  93. {paramrf-0.35.4 → paramrf-0.36.0}/docs/agents/domain.md +0 -0
  94. {paramrf-0.35.4 → paramrf-0.36.0}/docs/agents/issue-tracker.md +0 -0
  95. {paramrf-0.35.4 → paramrf-0.36.0}/docs/agents/triage-labels.md +0 -0
  96. {paramrf-0.35.4 → paramrf-0.36.0}/docs/conf.py +0 -0
  97. {paramrf-0.35.4 → paramrf-0.36.0}/docs/core_concepts/core_primitives.rst +0 -0
  98. {paramrf-0.35.4 → paramrf-0.36.0}/docs/core_concepts/index.rst +0 -0
  99. {paramrf-0.35.4 → paramrf-0.36.0}/docs/core_concepts/jax_overview.rst +0 -0
  100. {paramrf-0.35.4 → paramrf-0.36.0}/docs/core_concepts/optimization_and_inference.rst +0 -0
  101. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/cascading_and_terminating.rst +0 -0
  102. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/circuit_clc.png +0 -0
  103. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/circuit_models.rst +0 -0
  104. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/custom_models.rst +0 -0
  105. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/index.rst +0 -0
  106. {paramrf-0.35.4 → paramrf-0.36.0}/docs/examples/multiple_models_one_parameter_set.rst +0 -0
  107. {paramrf-0.35.4 → paramrf-0.36.0}/docs/index.rst +0 -0
  108. {paramrf-0.35.4 → paramrf-0.36.0}/docs/license.rst +0 -0
  109. {paramrf-0.35.4 → paramrf-0.36.0}/docs/make.bat +0 -0
  110. {paramrf-0.35.4 → paramrf-0.36.0}/docs/research/conductor-loss-alternatives.md +0 -0
  111. {paramrf-0.35.4 → paramrf-0.36.0}/docs/research/holloway1994.pdf +0 -0
  112. {paramrf-0.35.4 → paramrf-0.36.0}/docs/research/microstrip-loss-conventions.md +0 -0
  113. {paramrf-0.35.4 → paramrf-0.36.0}/docs/research/precision-coax-microstrip-10-500mhz.md +0 -0
  114. {paramrf-0.35.4 → paramrf-0.36.0}/docs/skrf_comparison/index.rst +0 -0
  115. {paramrf-0.35.4 → paramrf-0.36.0}/docs/skrf_comparison/overview.rst +0 -0
  116. {paramrf-0.35.4 → paramrf-0.36.0}/docs/skrf_comparison/performance.rst +0 -0
  117. {paramrf-0.35.4 → paramrf-0.36.0}/docs/tutorials/data/CBN-1.5FT-SMSM.s2p +0 -0
  118. {paramrf-0.35.4 → paramrf-0.36.0}/docs/tutorials/data/on-chip-inductor.s2p +0 -0
  119. {paramrf-0.35.4 → paramrf-0.36.0}/docs/tutorials/index.rst +0 -0
  120. {paramrf-0.35.4 → paramrf-0.36.0}/paper/paper.bib +0 -0
  121. {paramrf-0.35.4 → paramrf-0.36.0}/paper/paper.md +0 -0
  122. {paramrf-0.35.4 → paramrf-0.36.0}/paper/rlc.png +0 -0
  123. {paramrf-0.35.4 → paramrf-0.36.0}/paramrf.egg-info/dependency_links.txt +0 -0
  124. {paramrf-0.35.4 → paramrf-0.36.0}/paramrf.egg-info/top_level.txt +0 -0
  125. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/constraints.py +0 -0
  126. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/covariance_kernels.py +0 -0
  127. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/__init__.py +0 -0
  128. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/result.py +0 -0
  129. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/routers.py +0 -0
  130. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/fitting/targets.py +0 -0
  131. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/frequency.py +0 -0
  132. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/__init__.py +0 -0
  133. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/result.py +0 -0
  134. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/sample.py +0 -0
  135. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/solvers/__init__.py +0 -0
  136. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/solvers/blackjax.py +0 -0
  137. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/infer/solvers/polychord.py +0 -0
  138. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/losses.py +0 -0
  139. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/__init__.py +0 -0
  140. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/conductor.py +0 -0
  141. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/dielectric.py +0 -0
  142. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/properties.py +0 -0
  143. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/roughness.py +0 -0
  144. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/substrate.py +0 -0
  145. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/materials/surface_impedance.py +0 -0
  146. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/__init__.py +0 -0
  147. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/aggregations.py +0 -0
  148. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/bessel.py +0 -0
  149. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/conversions.py +0 -0
  150. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/losses.py +0 -0
  151. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/math/misc.py +0 -0
  152. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/__init__.py +0 -0
  153. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/base.py +0 -0
  154. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/bridge.py +0 -0
  155. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/callable.py +0 -0
  156. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/delegated.py +0 -0
  157. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/derived.py +0 -0
  158. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/static.py +0 -0
  159. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/adapters/wrapped.py +0 -0
  160. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/__init__.py +0 -0
  161. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/__init__.py +0 -0
  162. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/base.py +0 -0
  163. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/coaxial.py +0 -0
  164. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/empirical.py +0 -0
  165. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/ideal.py +0 -0
  166. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/microstrip.py +0 -0
  167. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/nodal.py +0 -0
  168. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/nonuniform.py +0 -0
  169. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/planar.py +0 -0
  170. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/profiles.py +0 -0
  171. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lines/stripline.py +0 -0
  172. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/lumped.py +0 -0
  173. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/components/sections.py +0 -0
  174. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/__init__.py +0 -0
  175. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/__init__.py +0 -0
  176. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/__init__.py +0 -0
  177. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/base.py +0 -0
  178. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/solvers/__init__.py +0 -0
  179. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/solvers/nodal.py +0 -0
  180. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/circuit/solvers/scattering.py +0 -0
  181. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/interconnected/terminated.py +0 -0
  182. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/nodal.py +0 -0
  183. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/topological.py +0 -0
  184. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/composite/transformed.py +0 -0
  185. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/surrogates/__init__.py +0 -0
  186. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/surrogates/expansion.py +0 -0
  187. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/models/surrogates/rational.py +0 -0
  188. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/modules/base.py +0 -0
  189. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/network_collection.py +0 -0
  190. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/noise_models.py +0 -0
  191. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/__init__.py +0 -0
  192. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/minimize.py +0 -0
  193. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/result.py +0 -0
  194. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/solvers/__init__.py +0 -0
  195. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/solvers/jaxopt.py +0 -0
  196. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/solvers/optimistix.py +0 -0
  197. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/optimize/solvers/scipy.py +0 -0
  198. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/problems.py +0 -0
  199. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/rf/__init__.py +0 -0
  200. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/rf/conversions.py +0 -0
  201. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/rf/mna.py +0 -0
  202. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/serialization.py +0 -0
  203. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/terms.py +0 -0
  204. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/types.py +0 -0
  205. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/__init__.py +0 -0
  206. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/array.py +0 -0
  207. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/debug.py +0 -0
  208. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/network.py +0 -0
  209. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/random.py +0 -0
  210. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/rf.py +0 -0
  211. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/utils/type.py +0 -0
  212. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/viz/__init__.py +0 -0
  213. {paramrf-0.35.4 → paramrf-0.36.0}/pmrf/viz/plots.py +0 -0
  214. {paramrf-0.35.4 → paramrf-0.36.0}/setup.cfg +0 -0
  215. {paramrf-0.35.4 → paramrf-0.36.0}/tests/__init__.py +0 -0
  216. {paramrf-0.35.4 → paramrf-0.36.0}/tests/_jit.py +0 -0
  217. {paramrf-0.35.4 → paramrf-0.36.0}/tests/data/10m_cable.s2p +0 -0
  218. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_autodiff.py +0 -0
  219. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_conversions.py +0 -0
  220. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_covariance_kernels.py +0 -0
  221. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_dc_limits.py +0 -0
  222. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_fitting_minimize.py +0 -0
  223. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_fitting_routers.py +0 -0
  224. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_frequency.py +0 -0
  225. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_materials/test_conductor.py +0 -0
  226. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_materials/test_dielectric.py +0 -0
  227. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_materials/test_serialization.py +0 -0
  228. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_materials/test_substrate.py +0 -0
  229. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_materials/test_surface_impedance.py +0 -0
  230. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_math/test_bessel.py +0 -0
  231. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_model.py +0 -0
  232. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_adapters.py +0 -0
  233. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_circuit_nodal.py +0 -0
  234. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_circuit_port_order.py +0 -0
  235. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_circuit_scattering.py +0 -0
  236. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_current_distribution.py +0 -0
  237. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_interconnected.py +0 -0
  238. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_lines.py +0 -0
  239. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_lines_skrf_matrix.py +0 -0
  240. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_lumped.py +0 -0
  241. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_nodal.py +0 -0
  242. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_profiles.py +0 -0
  243. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_repeated_cascade.py +0 -0
  244. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_sections.py +0 -0
  245. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_transformed.py +0 -0
  246. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_models/test_transformers.py +0 -0
  247. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_optimize_minimize.py +0 -0
  248. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_serialization.py +0 -0
  249. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_terms.py +0 -0
  250. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_utils/test_compress.py +0 -0
  251. {paramrf-0.35.4 → paramrf-0.36.0}/tests/test_utils/test_tree.py +0 -0
@@ -3,6 +3,7 @@ name: Deploy Sphinx Docs
3
3
  on:
4
4
  push:
5
5
  branches: [main]
6
+ tags: [ "v*" ]
6
7
 
7
8
  permissions:
8
9
  contents: write
@@ -27,7 +28,6 @@ jobs:
27
28
  - name: Install dependencies
28
29
  run: |
29
30
  pip install -e ".[docs]"
30
- pip install "git+https://github.com/gvcallen/distreqx.git"
31
31
 
32
32
  - name: Build docs
33
33
  run: |
@@ -0,0 +1,62 @@
1
+ name: Run Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: [ "v*" ]
7
+ paths-ignore:
8
+ - "docs/**"
9
+ - "paper/**"
10
+ - "**.md"
11
+ - "**.rst"
12
+ pull_request:
13
+ branches: [main]
14
+ paths-ignore:
15
+ - "docs/**"
16
+ - "paper/**"
17
+ - "**.md"
18
+ - "**.rst"
19
+
20
+ concurrency:
21
+ group: ${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
23
+
24
+ jobs:
25
+ test:
26
+ runs-on: ubuntu-latest
27
+
28
+ steps:
29
+ - name: Checkout repo
30
+ uses: actions/checkout@v4
31
+
32
+ - name: Install Compilers and MPI
33
+ run: |
34
+ sudo apt-get update
35
+ sudo apt-get install -y gfortran libopenmpi-dev openmpi-bin
36
+
37
+ - name: Set up Python
38
+ uses: actions/setup-python@v5
39
+ with:
40
+ python-version: '3.11'
41
+ cache: pip
42
+ cache-dependency-path: pyproject.toml
43
+
44
+ - name: Install dependencies and smoke test package import
45
+ run: scripts/install-test-deps.sh
46
+
47
+ # Each run saves under its own key and restores the newest earlier one, so the cache
48
+ # follows the code. conftest.py caps its size.
49
+ - name: Restore JAX compilation cache
50
+ uses: actions/cache@v4
51
+ with:
52
+ path: .jax_cache
53
+ key: jax-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}-${{ github.sha }}
54
+ restore-keys: |
55
+ jax-${{ runner.os }}-${{ hashFiles('pyproject.toml') }}-
56
+ jax-${{ runner.os }}-
57
+
58
+ - name: Run Pytest
59
+ run: |
60
+ python -m pytest -rs -n auto
61
+ env:
62
+ PMRF_TESTS_NO_SKIPS: "1"
@@ -190,3 +190,6 @@ skills-lock.json
190
190
  .secrets/
191
191
  *.token
192
192
  .env.local
193
+
194
+ # JAX persistent compilation cache (tests/conftest.py)
195
+ .jax_cache/
@@ -0,0 +1,90 @@
1
+ # AGENTS.md
2
+
3
+ **ParamRF** (`pmrf`) is a JAX-native RF modelling framework: frequency-domain circuit
4
+ simulation, optimisation, fitting, and inference. Models are Equinox modules — immutable
5
+ dataclasses that are also JAX PyTrees. Built on `jax`, `equinox`, and
6
+ [`parax`](https://gvcallen.github.io/parax) (the parameter/constraint layer).
7
+
8
+ ## Breaking changes are fine
9
+
10
+ Pre-1.0. No backwards-compatibility shims, deprecation aliases or legacy code paths
11
+ unless asked. Prefer the clean design, within the issue's seam.
12
+
13
+ ## Seams
14
+
15
+ Each issue names one seam: a file, a set of files, or a folder. If the work needs a
16
+ change outside it, stop and ask.
17
+
18
+ `CONTEXT.md` and ADRs (architecture decision records, `docs/adr/`) are edited only by
19
+ the reviewer, in their own commit. If you need a domain term that isn't in the issue,
20
+ an ADR or `CONTEXT.md`, that's a design decision: stop and ask.
21
+
22
+ Start every PR body with `## Cross-seam`, listing each file changed outside the issue's
23
+ seam with the ADR or issue line that allows it, or `DECISION NEEDED`. Write `none` if
24
+ there are none.
25
+
26
+ ## Commands
27
+
28
+ ```bash
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
+ .venv/bin/python -c "import pmrf" # import smoke check
32
+ ```
33
+
34
+ CI runs the full suite on every PR. Compilation dominates test time, so `tests/conftest.py`
35
+ keeps JAX's persistent compilation cache in `.jax_cache/`: the first run fills it (about 4 min
36
+ with `-n 4`) and later runs take about 2 min. Deleting it is always safe.
37
+
38
+ No linter or formatter is configured. Match the style of surrounding code.
39
+
40
+ ## Commits
41
+
42
+ Do not add yourself as an author. No `Co-Authored-By` trailer, no session link, no
43
+ tool attribution.
44
+
45
+ ## Source layout
46
+
47
+ Real code lives in `pmrf/`. `build/` and `dist/` hold stale copies of it — searches will
48
+ hit them, but never read or edit them as source.
49
+
50
+ ## Naming
51
+
52
+ - `Solver` — reserved for classes that actually solve a system (`GlobalMNACircuitSolver`).
53
+ - `Formulation` — closed-form physics strategy objects.
54
+ - `Abstract` — prefixes an ABC unless it is domain terminology. `Model` is the exception.
55
+
56
+ ## Documentation
57
+
58
+ Numpydoc docstrings. Maths is written `$$...$$` and rendered by `sphinx-math-dollar`.
59
+ Physics classes carry a `**Mathematical Formulation**` section stating the equations they
60
+ implement and a `References` section citing the source paper; match that. Fields are
61
+ documented with `#:` comments directly above them.
62
+
63
+ ## Tests
64
+
65
+ `tests/` mirrors the package. When touching physics, validate against `scikit-rf` rather
66
+ than against recorded ParamRF output, which only locks in current behaviour. Record
67
+ tolerances per case; do not loosen a global tolerance to make one case pass.
68
+
69
+ **scikit-rf is guidance, not ground truth.** It makes its own approximations and
70
+ modelling choices, and it has been wrong before. When a comparison disagrees, read the
71
+ scikit-rf source (not just its docstring) and check both implementations against the
72
+ cited paper. If ParamRF is wrong, fix it; if scikit-rf is, or the two deliberately model
73
+ different things, say so in the test with the reason. Never widen a tolerance until the
74
+ difference is explained.
75
+
76
+ ## Issues and docs
77
+
78
+ ### Issue tracker
79
+
80
+ Issues live as GitHub issues on `gvcallen/paramrf`, managed with the `gh` CLI. See
81
+ `docs/agents/issue-tracker.md`.
82
+
83
+ ### Triage labels
84
+
85
+ See `docs/agents/triage-labels.md`.
86
+
87
+ ### Domain docs
88
+
89
+ One `CONTEXT.md` and one `docs/adr/` at the repo root; either may not exist yet. See
90
+ `docs/agents/domain.md`.
@@ -0,0 +1,90 @@
1
+ # AGENTS.md
2
+
3
+ **ParamRF** (`pmrf`) is a JAX-native RF modelling framework: frequency-domain circuit
4
+ simulation, optimisation, fitting, and inference. Models are Equinox modules — immutable
5
+ dataclasses that are also JAX PyTrees. Built on `jax`, `equinox`, and
6
+ [`parax`](https://gvcallen.github.io/parax) (the parameter/constraint layer).
7
+
8
+ ## Breaking changes are fine
9
+
10
+ Pre-1.0. No backwards-compatibility shims, deprecation aliases or legacy code paths
11
+ unless asked. Prefer the clean design, within the issue's seam.
12
+
13
+ ## Seams
14
+
15
+ Each issue names one seam: a file, a set of files, or a folder. If the work needs a
16
+ change outside it, stop and ask.
17
+
18
+ `CONTEXT.md` and ADRs (architecture decision records, `docs/adr/`) are edited only by
19
+ the reviewer, in their own commit. If you need a domain term that isn't in the issue,
20
+ an ADR or `CONTEXT.md`, that's a design decision: stop and ask.
21
+
22
+ Start every PR body with `## Cross-seam`, listing each file changed outside the issue's
23
+ seam with the ADR or issue line that allows it, or `DECISION NEEDED`. Write `none` if
24
+ there are none.
25
+
26
+ ## Commands
27
+
28
+ ```bash
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
+ .venv/bin/python -c "import pmrf" # import smoke check
32
+ ```
33
+
34
+ CI runs the full suite on every PR. Compilation dominates test time, so `tests/conftest.py`
35
+ keeps JAX's persistent compilation cache in `.jax_cache/`: the first run fills it (about 4 min
36
+ with `-n 4`) and later runs take about 2 min. Deleting it is always safe.
37
+
38
+ No linter or formatter is configured. Match the style of surrounding code.
39
+
40
+ ## Commits
41
+
42
+ Do not add yourself as an author. No `Co-Authored-By` trailer, no session link, no
43
+ tool attribution.
44
+
45
+ ## Source layout
46
+
47
+ Real code lives in `pmrf/`. `build/` and `dist/` hold stale copies of it — searches will
48
+ hit them, but never read or edit them as source.
49
+
50
+ ## Naming
51
+
52
+ - `Solver` — reserved for classes that actually solve a system (`GlobalMNACircuitSolver`).
53
+ - `Formulation` — closed-form physics strategy objects.
54
+ - `Abstract` — prefixes an ABC unless it is domain terminology. `Model` is the exception.
55
+
56
+ ## Documentation
57
+
58
+ Numpydoc docstrings. Maths is written `$$...$$` and rendered by `sphinx-math-dollar`.
59
+ Physics classes carry a `**Mathematical Formulation**` section stating the equations they
60
+ implement and a `References` section citing the source paper; match that. Fields are
61
+ documented with `#:` comments directly above them.
62
+
63
+ ## Tests
64
+
65
+ `tests/` mirrors the package. When touching physics, validate against `scikit-rf` rather
66
+ than against recorded ParamRF output, which only locks in current behaviour. Record
67
+ tolerances per case; do not loosen a global tolerance to make one case pass.
68
+
69
+ **scikit-rf is guidance, not ground truth.** It makes its own approximations and
70
+ modelling choices, and it has been wrong before. When a comparison disagrees, read the
71
+ scikit-rf source (not just its docstring) and check both implementations against the
72
+ cited paper. If ParamRF is wrong, fix it; if scikit-rf is, or the two deliberately model
73
+ different things, say so in the test with the reason. Never widen a tolerance until the
74
+ difference is explained.
75
+
76
+ ## Issues and docs
77
+
78
+ ### Issue tracker
79
+
80
+ Issues live as GitHub issues on `gvcallen/paramrf`, managed with the `gh` CLI. See
81
+ `docs/agents/issue-tracker.md`.
82
+
83
+ ### Triage labels
84
+
85
+ See `docs/agents/triage-labels.md`.
86
+
87
+ ### Domain docs
88
+
89
+ One `CONTEXT.md` and one `docs/adr/` at the repo root; either may not exist yet. See
90
+ `docs/agents/domain.md`.
@@ -20,6 +20,8 @@ for saved results, ties and selectors.
20
20
  Where a parameter's number lives. Every surface defaults to **declared**.
21
21
 
22
22
  - **raw**: the latent, unbounded array optimisers and samplers move through.
23
+ ParamRF defines it: a parameter's prior whitens it, and attaching a joint
24
+ prior redefines it for the parameters under that prior (ADR-0005).
23
25
  - **declared**: the number as written, in the units the parameter's scale
24
26
  declares (2.0 for 2 pF). Construction, bounds, priors and `Param.value` are
25
27
  in declared space.
@@ -70,8 +72,8 @@ Two operations read a tied tree back, and they are not the same thing.
70
72
  `dict`, still parameterised.
71
73
  - **Evaluation** (`prf.unwrap`): every parameter becomes its physical value.
72
74
  The result is numbers, not priors, and nothing rebuilt from it is
73
- parameterised. A joint prior (`prf.modules.Probabilistic`) is discharged the
74
- same way and for the same reason, so resolve leaves it standing.
75
+ parameterised. A joint prior is dropped the same way and for the same
76
+ reason, so resolve leaves it standing.
75
77
 
76
78
  Resolve is the one ordinary modelling code wants; `prf.unwrap` is a low-level
77
79
  evaluation primitive. A tie's target resolves to a plain value either way — it
@@ -79,6 +81,19 @@ is derived, so it has no prior of its own.
79
81
 
80
82
  *Avoid:* "unwrap" for reading a tied container; "apply the ties" for evaluation.
81
83
 
84
+ ### Prior and joint prior
85
+
86
+ `prf.prior` attaches a prior to the parameters a selector picks (ADR-0005). A
87
+ scalar distribution gives each of them its own prior. A distribution whose
88
+ event size equals the number of parameters is a **joint prior** over them: a
89
+ wrapper (`prf.modules.Probabilistic`) around the unchanged tree, so every
90
+ parameter keeps its name. A joint prior replaces its parameters' own priors,
91
+ and its `space` says which space its distribution is over. Raw space for its
92
+ parameters becomes the distribution's whitened space.
93
+
94
+ *Avoid:* "covered parameters" (say "the parameters under a joint prior");
95
+ "joint target" (the old collapsing node).
96
+
82
97
  ### Derived model
83
98
 
84
99
  A model computed from a **base** model and **new parameters** by a function,
@@ -91,7 +106,7 @@ named by its keyword. Used to derive a more complete model from a nominal one
91
106
 
92
107
  ### Parameter values
93
108
 
94
- `prf.param_values`: a name-keyed dict of arrays in one space, the form values
109
+ `prf.values`: a name-keyed dict of arrays in one space, the form values
95
110
  take when crossing ParamRF's boundary. Not flattened; a 1-D vector exists only
96
111
  inside adapters that need one.
97
112
 
@@ -167,4 +182,6 @@ paper with no ParamRF objects in sight.
167
182
  `docs/adr/` records the decisions behind these layers. Read
168
183
  `docs/adr/0001-line-modelling-architecture.md` before changing a strategy
169
184
  interface or a default, and `docs/adr/0002-parameter-api.md` before adding a
170
- method, a public function or a value space.
185
+ method, a public function or a value space. Read
186
+ `docs/adr/0005-priors-by-name.md` before changing how priors are attached or
187
+ scored.
@@ -8,7 +8,7 @@ ParamRF builds on top of JAX and Equinox's functional style. If you are coming f
8
8
 
9
9
  1. **Fork and Clone:** Fork the repository on GitHub and clone it locally.
10
10
  2. **Virtual Environment:** Set up a virtual environment using Python 3.11+.
11
- 3. **Install Dependencies:** Install the package in editable mode with the same test environment CI uses, including the pinned `distreqx` fork, PolyChord and blackjax. PolyChord needs Fortran and MPI compilers (like `mpifort` and `mpicxx`):
11
+ 3. **Install Dependencies:** Install the package in editable mode with the same test environment CI uses, including PolyChord and blackjax. PolyChord needs Fortran and MPI compilers (like `mpifort` and `mpicxx`):
12
12
 
13
13
  scripts/install-test-deps.sh
14
14
  pip install -e .[docs]
@@ -1,19 +1,18 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramrf
3
- Version: 0.35.4
3
+ Version: 0.36.0
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.10.8
10
+ Requires-Dist: parax>=0.11.1
11
11
  Requires-Dist: threadpoolctl
12
12
  Requires-Dist: eqxpress
13
13
  Requires-Dist: jax
14
14
  Requires-Dist: jaxtyping
15
15
  Requires-Dist: equinox
16
- Requires-Dist: distreqx
17
16
  Requires-Dist: optimistix
18
17
  Requires-Dist: lineax
19
18
  Requires-Dist: jaxopt
@@ -35,11 +34,14 @@ Requires-Dist: matplotlib; extra == "docs"
35
34
  Requires-Dist: jupyter-sphinx; extra == "docs"
36
35
  Provides-Extra: tests
37
36
  Requires-Dist: pytest; extra == "tests"
37
+ Requires-Dist: pytest-xdist; extra == "tests"
38
+ Requires-Dist: filelock; extra == "tests"
38
39
  Requires-Dist: ipython; extra == "tests"
39
40
  Requires-Dist: scikit-rf; extra == "tests"
40
41
  Requires-Dist: anesthetic; extra == "tests"
41
42
  Requires-Dist: mpi4py; extra == "tests"
42
43
  Requires-Dist: blackjax; extra == "tests"
44
+ Requires-Dist: fleqx; extra == "tests"
43
45
  Dynamic: license-file
44
46
 
45
47
  .. title:: Home
@@ -113,7 +115,7 @@ The code below demonstrate how to define and optimize an RLC model to satisfy a
113
115
  model.plot_s_db(plot_freq, m=0, n=0, label='initial')
114
116
  result.model.plot_s_db(plot_freq, m=0, n=0, label='optimized')
115
117
 
116
- print(prf.param_values(result.model))
118
+ print(prf.values(result.model))
117
119
 
118
120
  Next steps
119
121
  ----------
@@ -125,12 +127,6 @@ Optional dependencies
125
127
  ---------------------
126
128
  Several additional dependencies are required/recommended for more advanced use-cases.
127
129
 
128
- For Bayesian inference, you may need this fork of *distreqx*:
129
-
130
- .. code-block:: bash
131
-
132
- $ pip install git+https://github.com/gvcallen/distreqx
133
-
134
130
  For *BlackJAX*'s Bayesian solvers:
135
131
 
136
132
  .. code-block:: bash
@@ -69,7 +69,7 @@ The code below demonstrate how to define and optimize an RLC model to satisfy a
69
69
  model.plot_s_db(plot_freq, m=0, n=0, label='initial')
70
70
  result.model.plot_s_db(plot_freq, m=0, n=0, label='optimized')
71
71
 
72
- print(prf.param_values(result.model))
72
+ print(prf.values(result.model))
73
73
 
74
74
  Next steps
75
75
  ----------
@@ -81,12 +81,6 @@ Optional dependencies
81
81
  ---------------------
82
82
  Several additional dependencies are required/recommended for more advanced use-cases.
83
83
 
84
- For Bayesian inference, you may need this fork of *distreqx*:
85
-
86
- .. code-block:: bash
87
-
88
- $ pip install git+https://github.com/gvcallen/distreqx
89
-
90
84
  For *BlackJAX*'s Bayesian solvers:
91
85
 
92
86
  .. code-block:: bash
@@ -133,16 +133,16 @@ not a replacement: its target is recomputed from its source every time the
133
133
  model is unwrapped. A relation that needs a quantity the model does not yet hold
134
134
  is a derived model (`prf.derived`, ADR-0003), not a tie.
135
135
 
136
- ### 4. Reading: `prf.params` and `prf.param_values`
136
+ ### 4. Reading: `prf.params` and `prf.values`
137
137
 
138
138
  ```python
139
139
  prf.params(model, where='*', *, free_only=False) # dict[str, Param]
140
- prf.param_values(model, where='*', *, free_only=False, space='declared') # dict[str, Array]
140
+ prf.values(model, where='*', *, free_only=False, space='declared') # dict[str, Array]
141
141
  prf.log_prior(model, *, space='declared') # scalar
142
142
  ```
143
143
 
144
144
  A user thinks "the parameters of my model", so `params` returns `Param`
145
- objects, whose `repr` shows value, bounds and prior. `param_values` is what
145
+ objects, whose `repr` shows value, bounds and prior. `values` is what
146
146
  `update` accepts and what optimisers use; a bare `values` was rejected as too
147
147
  vague at top level, where it could mean S-parameter data. `named_params`'
148
148
  `full_params` and `namespace_separator` are dropped.
@@ -150,7 +150,7 @@ vague at top level, where it could mean S-parameter data. `named_params`'
150
150
  The documented identity, which is also the regression test of decision 10:
151
151
 
152
152
  ```python
153
- prf.update(m, prf.param_values(m, space=s), space=s) # same structure, same cache key
153
+ prf.update(m, prf.values(m, space=s), space=s) # same structure, same cache key
154
154
  ```
155
155
 
156
156
  All functions are defined in `pmrf.parameters` and re-exported at top level.
@@ -165,7 +165,7 @@ All functions are defined in `pmrf.parameters` and re-exported at top level.
165
165
 
166
166
  `declared` is the default everywhere, and every user-facing surface agrees with
167
167
  construction: `Param(value=...)`, bounds, priors, `repr`, `Param.value`,
168
- `param_values` and `update`. Distributions and bounds are authored in declared
168
+ `values` and `update`. Distributions and bounds are authored in declared
169
169
  space.
170
170
 
171
171
  `Param` gets one property per space: `value` (declared), `physical_value` and
@@ -218,7 +218,7 @@ Raveling to a 1-D vector stays inside the adapters that need it, such as the
218
218
  SciPy solver (`pmrf/optimize/solvers/scipy.py`) and non-JAX samplers.
219
219
  `prf.flatten` and `FlatParams` (#142) are not added. A public ravel helper, with
220
220
  one name per array element, can be added when a non-JAX consumer needs it; it
221
- would sit on top of `param_values`, not replace it.
221
+ would sit on top of `values`, not replace it.
222
222
 
223
223
  The substance of #142 is kept: the raw-space log prior with the Jacobian and
224
224
  scale terms, name alignment, and a single implementation behind the minimiser
@@ -0,0 +1,162 @@
1
+ # ADR-0005: Priors are attached by name, and a joint prior keeps its parameters
2
+
3
+ Status: accepted (2026-09)
4
+
5
+ ## Context
6
+
7
+ A fit's posterior is often the next fit's prior. The driving case: a normalizing
8
+ flow is trained on one fit's samples, over 20 to 40 named free parameters, and
9
+ must be the prior of the next fit under MCMC and under PolyChord. A flow is one
10
+ example; the requirement is any joint distribution over named parameters.
11
+
12
+ `prf.modules.Probabilistic` was the only way to attach a joint prior. It
13
+ replaces its target sub-tree with a `parax.Probabilize` node, which unwraps the
14
+ sub-tree and stores one raw value for all of it. That fitted Parax's own style,
15
+ where parameters have no names and a sampler moves through a partitioned
16
+ pytree. It does not fit ParamRF since ADR-0002, where everything is addressed by
17
+ parameter name and solvers see a name-keyed dict:
18
+
19
+ - The covered parameters lose their names. A prior over the root is one
20
+ parameter named `''`, valued as a whole model.
21
+ - A `Fixed` parameter inside the target breaks construction.
22
+ - The name resolver, `log_prior` and `resolve` special-case the collapsed node.
23
+ - Hypercube samplers reject it, since it is not a `Param` with an `icdf`.
24
+ - A joint prior over parameters in different sub-models needs their common
25
+ parent as the target, and absorbs everything below it.
26
+
27
+ The one thing it does well must be kept: its raw value is the distribution's
28
+ whitened space (for a flow, its base `z`), so optimisers and samplers move in
29
+ well-conditioned coordinates.
30
+
31
+ ## Decision
32
+
33
+ ### `prf.prior`
34
+
35
+ `prf.prior(tree, names, distribution, space='declared')` returns a copy of a
36
+ tree with a prior attached to the parameters that `names` selects. `names` is a
37
+ selector, as for `prf.update`. It is the one way to attach a prior after
38
+ construction, whether one-dimensional or joint, and its form follows `prf.tie`.
39
+
40
+ The distribution's event size decides which:
41
+
42
+ - **Scalar event**: each selected parameter gets its own prior, as if built with
43
+ `prf.Random`. Its raw space becomes the new prior's whitening, as for
44
+ `prf.Random`, and the prior is truncated to the parameter's existing bounds so
45
+ the bounds still hold.
46
+ - **Event size equal to the number of selected parameters**: a **joint prior**
47
+ over them.
48
+ - Anything else raises.
49
+
50
+ ### A joint prior keeps its parameters
51
+
52
+ A joint prior is a wrapper around the unchanged tree, holding the distribution,
53
+ the parameter names and the space: `Probabilistic`, rewritten. The wrapper is
54
+ transparent to the name resolver, as `Tied` is. So:
55
+
56
+ - Every parameter keeps its name and stays a parameter. `prf.params`,
57
+ `prf.values` and `prf.update` work as before.
58
+ - The prior stores names, not paths. With an explicit sequence of names, the
59
+ distribution's vector is in that order; a glob expands to sorted names.
60
+ - Several joint priors may be attached, one wrapper each, over disjoint sets of
61
+ parameters. A parameter under two joint priors raises.
62
+ - The joint prior **replaces** its parameters' own priors. Multiplying them in
63
+ would count the earlier fit's priors twice, since its posterior already
64
+ includes them.
65
+
66
+ ### Space
67
+
68
+ `space` states the space the distribution is over: `'raw'`, `'declared'` or
69
+ `'physical'`. ParamRF applies the mappings between spaces, with their
70
+ change-of-variables terms.
71
+
72
+ `'raw'` means the parameters' raw space as it was just before `prf.prior` was
73
+ called, which is what `prf.values(..., space='raw')` returned then. A
74
+ distribution over raw space is only meaningful with respect to that raw to
75
+ declared mapping, so the mapping is kept when the prior replaces the
76
+ parameters' own priors, including any whitening their old priors gave it.
77
+
78
+ ### Attaching a joint prior redefines raw space
79
+
80
+ For the parameters under a joint prior, raw space becomes the distribution's
81
+ whitened space, inferred as for a one-dimensional prior
82
+ (`parax.constraints.infer_distribution_constraint`): a flow's base `z`, the
83
+ Cholesky-whitened space of a multivariate normal, and so on. Where no whitening
84
+ is known, raw is the distribution's own space. Raw space is ParamRF's to define:
85
+ it is a latent space, usually whitened to some degree. Each parameter's raw value
86
+ is its entry in that vector, so it keeps its name.
87
+
88
+ The same word, raw, therefore names two spaces for these parameters: the one
89
+ `space='raw'` refers to (before attaching), and the one solvers move in (after).
90
+
91
+ ### Bounds
92
+
93
+ A parameter's bounds still hold under a joint prior, and its prior is exactly
94
+ normalised, so a hypercube sampler's evidence is exact. Solvers move in the
95
+ whitened space, which reaches the distribution's whole support, and a parameter
96
+ cannot hold a value outside its bounds, so the support must already lie inside
97
+ them:
98
+
99
+ - A distribution over raw space cannot leave the bounds: it reaches declared
100
+ space through the parameters' old raw to declared mappings. This is the
101
+ intended use, a flow trained on an earlier fit's raw samples.
102
+ - A distribution over declared or physical space is rejected by `prf.prior`
103
+ unless its support lies inside the parameters' bounds. A joint distribution
104
+ cut at the bounds has no exact normaliser, and an unnormalised one would bias
105
+ the evidence.
106
+
107
+ The check is against the parameters' current bounds. These do not yet record
108
+ whether a bound is the model's (validity, such as a positive width) or the
109
+ user's (a range, such as `prf.Bounded`), so the check treats every bound as
110
+ validity.
111
+
112
+ ### Hypercube samplers
113
+
114
+ A hypercube sampler maps the unit cube through a joint prior's block as
115
+ `u -> Normal(0, 1).icdf(u) -> whitening -> raw -> declared` whenever the
116
+ whitening ends in an independent standard-normal base. Parameters outside
117
+ joint priors keep their own `icdf`. A joint prior without such a base raises,
118
+ saying which structure is needed. This is built in ParamRF's sampler, not as a
119
+ distribution's `icdf`: the map is a cube transform, not a multivariate inverse
120
+ CDF.
121
+
122
+ ### Fixing and tying
123
+
124
+ - Fixing a parameter under a joint prior raises. Its fixed value does not fix
125
+ any one raw coordinate, and a hypercube sampler cannot draw from the
126
+ conditional. To fix it, marginalise the distribution first and attach it over
127
+ fewer parameters.
128
+ - Tying a parameter under a joint prior raises, whichever is applied first: the
129
+ distribution must control it.
130
+ - `prf.resolve` keeps a joint prior, since it is not a tie and does not change
131
+ what the parameters are. `prf.unwrap` drops it, as it drops every prior.
132
+
133
+ ## Rejected options
134
+
135
+ - **Polishing the collapsing `Probabilistic`** (keeping the names of the
136
+ parameters it absorbs). Names, `Fixed` and hypercube support all fight the
137
+ collapse; the collapse is what has to go.
138
+ - **A joint prior as a separate argument** (`prior=` on `log_prior` and
139
+ `sample`). Every consumer would have to pass it on, `prf.log_prior(model)`
140
+ would be silently wrong without it, and a saved model would lose its prior.
141
+ - **Solvers moving in the old raw space under a joint prior.** Simpler, but badly
142
+ conditioned for a flow, which is the main reason to use one.
143
+ - **Allowing fixed parameters under a joint prior for MCMC only.** The joint
144
+ density at the fixed value is the right conditional up to a constant, but with
145
+ whitened raw coordinates a fixed parameter fixes no coordinate.
146
+ - **Calling the pre-attach space `'unconstrained'`.** Inaccurate: it includes
147
+ the whitening from the old priors. The term is also on the avoid list.
148
+ - **`Transformed.icdf` in distreqx.** It would not be an inverse CDF, and it would
149
+ put ParamRF's sampler logic in another repository.
150
+
151
+ ## Consequences
152
+
153
+ - The old `Probabilistic` constructor (`target=`, `static=`, tuple targets) and
154
+ the `parax.Probabilize` node are removed, with no alias, along with the
155
+ special cases for them in the name resolver, `log_prior` and `resolve`.
156
+ - ADR-0003's claim that a joint prior over a derived model's base scores
157
+ unchanged still holds, and more simply: the base's names are the prior's names.
158
+ - A distribution over raw space is tied to the constraints and priors the
159
+ parameters had when it was trained. Changing them between fits changes what
160
+ it means, and ParamRF does not check this.
161
+ - ParamRF no longer uses Parax's subtree-level `Probabilize`. What Parax keeps
162
+ is a separate decision.