paramrf 0.36.6__tar.gz → 0.37.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 (268) hide show
  1. {paramrf-0.36.6 → paramrf-0.37.0}/CONTEXT.md +2 -2
  2. {paramrf-0.36.6 → paramrf-0.37.0}/CONTRIBUTING.md +2 -2
  3. {paramrf-0.36.6/paramrf.egg-info → paramrf-0.37.0}/PKG-INFO +2 -2
  4. {paramrf-0.36.6 → paramrf-0.37.0}/README.rst +2 -2
  5. {paramrf-0.36.6 → paramrf-0.37.0}/docs/api/index.rst +3 -11
  6. {paramrf-0.36.6 → paramrf-0.37.0}/docs/core_concepts/core_primitives.rst +7 -7
  7. {paramrf-0.36.6 → paramrf-0.37.0}/docs/core_concepts/optimization_and_inference.rst +3 -3
  8. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/custom_models.rst +1 -1
  9. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/discrepancy_prediction.rst +5 -7
  10. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/index.rst +2 -3
  11. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/model_optimization.rst +3 -3
  12. paramrf-0.37.0/docs/examples/shared_modules.rst +30 -0
  13. {paramrf-0.36.6 → paramrf-0.37.0}/docs/skrf_comparison/performance.rst +1 -1
  14. paramrf-0.37.0/docs/tutorials/3_discrepancy_transfer.ipynb +317 -0
  15. {paramrf-0.36.6 → paramrf-0.37.0}/docs/tutorials/index.rst +2 -1
  16. paramrf-0.37.0/docs/tutorials/line_internal_discrepancy.py +148 -0
  17. {paramrf-0.36.6/docs/examples → paramrf-0.37.0/docs/tutorials}/port_discrepancy.py +3 -6
  18. {paramrf-0.36.6 → paramrf-0.37.0}/paper/paper.md +2 -1
  19. {paramrf-0.36.6 → paramrf-0.37.0/paramrf.egg-info}/PKG-INFO +2 -2
  20. {paramrf-0.36.6 → paramrf-0.37.0}/paramrf.egg-info/SOURCES.txt +22 -16
  21. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/__init__.py +6 -19
  22. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/minimize.py +18 -18
  23. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/result.py +1 -1
  24. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/routers.py +3 -3
  25. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/sample.py +7 -7
  26. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/targets.py +1 -1
  27. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/result.py +2 -2
  28. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/sample.py +2 -2
  29. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/conductor.py +1 -1
  30. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/dielectric.py +1 -1
  31. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/roughness.py +1 -1
  32. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/substrate.py +1 -1
  33. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/__init__.py +9 -0
  34. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/base.py +1 -1
  35. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/base.py +1 -1
  36. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/coaxial.py +1 -1
  37. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/empirical.py +1 -1
  38. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/ideal.py +1 -1
  39. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/microstrip.py +1 -1
  40. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/profiles.py +1 -1
  41. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/stripline.py +1 -1
  42. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lumped.py +1 -1
  43. paramrf-0.37.0/pmrf/models/line_discrepancy.py +296 -0
  44. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/port_discrepancy.py +14 -8
  45. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/modules/wrapped.py +1 -1
  46. paramrf-0.37.0/pmrf/objectives/__init__.py +48 -0
  47. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/objectives}/evaluators.py +25 -25
  48. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/objectives}/problems.py +1 -1
  49. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/objectives}/terms.py +1 -1
  50. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/minimize.py +3 -3
  51. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/result.py +2 -2
  52. paramrf-0.36.6/pmrf/parameters.py → paramrf-0.37.0/pmrf/parameters/__init__.py +14 -14
  53. paramrf-0.37.0/pmrf/stats/__init__.py +74 -0
  54. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/covariance_kernels.py +5 -5
  55. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/discrepancy_models.py +7 -7
  56. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/likelihoods.py +1 -1
  57. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/linearization.py +4 -4
  58. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/noise_models.py +1 -1
  59. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/viz/plots.py +1 -1
  60. {paramrf-0.36.6 → paramrf-0.37.0}/pyproject.toml +1 -1
  61. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_box_space_solving.py +2 -2
  62. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_covariance_kernels.py +5 -5
  63. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_discrepancy_models.py +2 -2
  64. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_evaluators.py +6 -6
  65. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_fitting_minimize.py +6 -6
  66. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_fitting_sample.py +2 -2
  67. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_fitting_targets.py +17 -17
  68. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_infer_base.py +2 -2
  69. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_infer_sample.py +1 -1
  70. paramrf-0.37.0/tests/test_line_internal_discrepancy_example.py +38 -0
  71. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_linearization.py +5 -5
  72. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_map_priors.py +3 -3
  73. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_derived.py +2 -2
  74. paramrf-0.37.0/tests/test_models/test_line_discrepancy.py +275 -0
  75. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_naming.py +1 -1
  76. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_parameters.py +2 -2
  77. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_parameters_by_name.py +3 -3
  78. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_parameters_joint_prior.py +7 -7
  79. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_parameters_prior.py +2 -2
  80. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_parameters_validity.py +2 -2
  81. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_port_discrepancy_example.py +1 -1
  82. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_raw_space_solving.py +3 -3
  83. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_structural_updates.py +1 -1
  84. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_terms.py +7 -7
  85. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_transforms.py +5 -5
  86. paramrf-0.36.6/docs/examples/port_discrepancy.rst +0 -53
  87. paramrf-0.36.6/docs/examples/shared_substrates.rst +0 -50
  88. {paramrf-0.36.6 → paramrf-0.37.0}/.github/workflows/docs.yml +0 -0
  89. {paramrf-0.36.6 → paramrf-0.37.0}/.github/workflows/draft-pdf.yml +0 -0
  90. {paramrf-0.36.6 → paramrf-0.37.0}/.github/workflows/publish.yml +0 -0
  91. {paramrf-0.36.6 → paramrf-0.37.0}/.github/workflows/tests.yml +0 -0
  92. {paramrf-0.36.6 → paramrf-0.37.0}/.gitignore +0 -0
  93. {paramrf-0.36.6 → paramrf-0.37.0}/AGENTS.md +0 -0
  94. {paramrf-0.36.6 → paramrf-0.37.0}/CHANGELOG.md +0 -0
  95. {paramrf-0.36.6 → paramrf-0.37.0}/CITATION.cff +0 -0
  96. {paramrf-0.36.6 → paramrf-0.37.0}/CLAUDE.md +0 -0
  97. {paramrf-0.36.6 → paramrf-0.37.0}/LICENSE +0 -0
  98. {paramrf-0.36.6 → paramrf-0.37.0}/NOTICE +0 -0
  99. {paramrf-0.36.6 → paramrf-0.37.0}/assets/logo.png +0 -0
  100. {paramrf-0.36.6 → paramrf-0.37.0}/docs/Makefile +0 -0
  101. {paramrf-0.36.6 → paramrf-0.37.0}/docs/_static/custom.css +0 -0
  102. {paramrf-0.36.6 → paramrf-0.37.0}/docs/_templates/autosummary/class.rst +0 -0
  103. {paramrf-0.36.6 → paramrf-0.37.0}/docs/_templates/autosummary/function.rst +0 -0
  104. {paramrf-0.36.6 → paramrf-0.37.0}/docs/_templates/autosummary/module.rst +0 -0
  105. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0001-line-modelling-architecture.md +0 -0
  106. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0002-parameter-api.md +0 -0
  107. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0003-derived-models.md +0 -0
  108. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0004-profiled-lines.md +0 -0
  109. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0005-priors-by-name.md +0 -0
  110. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0006-reference-impedance.md +0 -0
  111. {paramrf-0.36.6 → paramrf-0.37.0}/docs/adr/0007-edge-values.md +0 -0
  112. {paramrf-0.36.6 → paramrf-0.37.0}/docs/agents/domain.md +0 -0
  113. {paramrf-0.36.6 → paramrf-0.37.0}/docs/agents/issue-tracker.md +0 -0
  114. {paramrf-0.36.6 → paramrf-0.37.0}/docs/agents/triage-labels.md +0 -0
  115. {paramrf-0.36.6 → paramrf-0.37.0}/docs/conf.py +0 -0
  116. {paramrf-0.36.6 → paramrf-0.37.0}/docs/core_concepts/index.rst +0 -0
  117. {paramrf-0.36.6 → paramrf-0.37.0}/docs/core_concepts/jax_overview.rst +0 -0
  118. {paramrf-0.36.6 → paramrf-0.37.0}/docs/core_concepts/parameter_names.rst +0 -0
  119. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/cascading_and_terminating.rst +0 -0
  120. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/circuit_clc.png +0 -0
  121. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/circuit_models.rst +0 -0
  122. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/derivatives_and_sweeps.rst +0 -0
  123. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/multiple_models_one_parameter_set.rst +0 -0
  124. {paramrf-0.36.6 → paramrf-0.37.0}/docs/examples/parameter_naming_and_model_manipulation.rst +0 -0
  125. {paramrf-0.36.6 → paramrf-0.37.0}/docs/index.rst +0 -0
  126. {paramrf-0.36.6 → paramrf-0.37.0}/docs/license.rst +0 -0
  127. {paramrf-0.36.6 → paramrf-0.37.0}/docs/make.bat +0 -0
  128. {paramrf-0.36.6 → paramrf-0.37.0}/docs/research/conductor-loss-alternatives.md +0 -0
  129. {paramrf-0.36.6 → paramrf-0.37.0}/docs/research/holloway1994.pdf +0 -0
  130. {paramrf-0.36.6 → paramrf-0.37.0}/docs/research/microstrip-loss-conventions.md +0 -0
  131. {paramrf-0.36.6 → paramrf-0.37.0}/docs/research/precision-coax-microstrip-10-500mhz.md +0 -0
  132. {paramrf-0.36.6 → paramrf-0.37.0}/docs/skrf_comparison/index.rst +0 -0
  133. {paramrf-0.36.6 → paramrf-0.37.0}/docs/skrf_comparison/overview.rst +0 -0
  134. {paramrf-0.36.6 → paramrf-0.37.0}/docs/tutorials/1_cable_fitting.ipynb +0 -0
  135. {paramrf-0.36.6 → paramrf-0.37.0}/docs/tutorials/2_chip_inductor_fitting.ipynb +0 -0
  136. {paramrf-0.36.6 → paramrf-0.37.0}/docs/tutorials/data/CBN-1.5FT-SMSM.s2p +0 -0
  137. {paramrf-0.36.6 → paramrf-0.37.0}/docs/tutorials/data/on-chip-inductor.s2p +0 -0
  138. {paramrf-0.36.6 → paramrf-0.37.0}/paper/paper.bib +0 -0
  139. {paramrf-0.36.6 → paramrf-0.37.0}/paper/rlc.png +0 -0
  140. {paramrf-0.36.6 → paramrf-0.37.0}/paramrf.egg-info/dependency_links.txt +0 -0
  141. {paramrf-0.36.6 → paramrf-0.37.0}/paramrf.egg-info/requires.txt +0 -0
  142. {paramrf-0.36.6 → paramrf-0.37.0}/paramrf.egg-info/top_level.txt +0 -0
  143. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/_solver_view.py +0 -0
  144. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/fitting/__init__.py +0 -0
  145. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/frequency.py +0 -0
  146. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/__init__.py +0 -0
  147. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/base.py +0 -0
  148. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/solvers/__init__.py +0 -0
  149. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/solvers/blackjax.py +0 -0
  150. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/infer/solvers/polychord.py +0 -0
  151. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/__init__.py +0 -0
  152. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/properties.py +0 -0
  153. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/materials/surface_impedance.py +0 -0
  154. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/__init__.py +0 -0
  155. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/aggregations.py +0 -0
  156. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/bessel.py +0 -0
  157. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/conversions.py +0 -0
  158. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/losses.py +0 -0
  159. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/math/misc.py +0 -0
  160. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/__init__.py +0 -0
  161. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/base.py +0 -0
  162. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/bridge.py +0 -0
  163. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/callable.py +0 -0
  164. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/delegated.py +0 -0
  165. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/derived.py +0 -0
  166. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/static.py +0 -0
  167. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/adapters/wrapped.py +0 -0
  168. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/__init__.py +0 -0
  169. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/ideal.py +0 -0
  170. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/__init__.py +0 -0
  171. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/nodal.py +0 -0
  172. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/nonuniform.py +0 -0
  173. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/lines/planar.py +0 -0
  174. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/components/sections.py +0 -0
  175. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/__init__.py +0 -0
  176. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/__init__.py +0 -0
  177. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/cascade.py +0 -0
  178. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/__init__.py +0 -0
  179. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/base.py +0 -0
  180. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/circuit.py +0 -0
  181. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/solvers/__init__.py +0 -0
  182. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/solvers/nodal.py +0 -0
  183. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/circuit/solvers/scattering.py +0 -0
  184. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/interconnected/terminated.py +0 -0
  185. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/nodal.py +0 -0
  186. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/topological.py +0 -0
  187. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/composite/transformed.py +0 -0
  188. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/surrogates/__init__.py +0 -0
  189. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/surrogates/expansion.py +0 -0
  190. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/models/surrogates/rational.py +0 -0
  191. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/modules/__init__.py +0 -0
  192. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/modules/base.py +0 -0
  193. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/network_collection.py +0 -0
  194. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/objectives}/losses.py +0 -0
  195. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/__init__.py +0 -0
  196. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/base.py +0 -0
  197. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/solvers/__init__.py +0 -0
  198. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/solvers/jaxopt.py +0 -0
  199. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/solvers/optimistix.py +0 -0
  200. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/optimize/solvers/scipy.py +0 -0
  201. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/parameters}/constraints.py +0 -0
  202. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/rf/__init__.py +0 -0
  203. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/rf/cascade.py +0 -0
  204. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/rf/conversions.py +0 -0
  205. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/rf/mna.py +0 -0
  206. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/serialization.py +0 -0
  207. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/bijectors.py +0 -0
  208. {paramrf-0.36.6/pmrf → paramrf-0.37.0/pmrf/stats}/distributions.py +0 -0
  209. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/types.py +0 -0
  210. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/__init__.py +0 -0
  211. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/array.py +0 -0
  212. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/debug.py +0 -0
  213. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/network.py +0 -0
  214. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/random.py +0 -0
  215. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/rf.py +0 -0
  216. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/transforms.py +0 -0
  217. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/tree.py +0 -0
  218. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/utils/type.py +0 -0
  219. {paramrf-0.36.6 → paramrf-0.37.0}/pmrf/viz/__init__.py +0 -0
  220. {paramrf-0.36.6 → paramrf-0.37.0}/scripts/benchmark_gp_marginal_likelihood.py +0 -0
  221. {paramrf-0.36.6 → paramrf-0.37.0}/scripts/install-test-deps.sh +0 -0
  222. {paramrf-0.36.6 → paramrf-0.37.0}/setup.cfg +0 -0
  223. {paramrf-0.36.6 → paramrf-0.37.0}/tests/__init__.py +0 -0
  224. {paramrf-0.36.6 → paramrf-0.37.0}/tests/_jit.py +0 -0
  225. {paramrf-0.36.6 → paramrf-0.37.0}/tests/conftest.py +0 -0
  226. {paramrf-0.36.6 → paramrf-0.37.0}/tests/data/10m_cable.s2p +0 -0
  227. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_autodiff.py +0 -0
  228. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_conversions.py +0 -0
  229. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_dc_limits.py +0 -0
  230. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_fitting_routers.py +0 -0
  231. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_frequency.py +0 -0
  232. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_materials/test_conductor.py +0 -0
  233. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_materials/test_dielectric.py +0 -0
  234. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_materials/test_serialization.py +0 -0
  235. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_materials/test_substrate.py +0 -0
  236. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_materials/test_surface_impedance.py +0 -0
  237. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_math/test_bessel.py +0 -0
  238. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_model.py +0 -0
  239. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_adapters.py +0 -0
  240. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_cascade.py +0 -0
  241. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_native_z0.py +0 -0
  242. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_nodal.py +0 -0
  243. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_port_order.py +0 -0
  244. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_scattering.py +0 -0
  245. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_shorted_ports.py +0 -0
  246. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_skrf_port_names.py +0 -0
  247. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_circuit_z0.py +0 -0
  248. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_current_distribution.py +0 -0
  249. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_edge_values.py +0 -0
  250. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_interconnected.py +0 -0
  251. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_lines.py +0 -0
  252. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_lines_skrf_matrix.py +0 -0
  253. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_lumped.py +0 -0
  254. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_nodal.py +0 -0
  255. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_port_discrepancy.py +0 -0
  256. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_profiles.py +0 -0
  257. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_rational.py +0 -0
  258. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_repeated_cascade.py +0 -0
  259. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_sections.py +0 -0
  260. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_transformed.py +0 -0
  261. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_models/test_transformers.py +0 -0
  262. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_module.py +0 -0
  263. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_optimize_base.py +0 -0
  264. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_optimize_minimize.py +0 -0
  265. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_serialization.py +0 -0
  266. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_utils/test_compress.py +0 -0
  267. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_utils/test_debug.py +0 -0
  268. {paramrf-0.36.6 → paramrf-0.37.0}/tests/test_utils/test_tree.py +0 -0
@@ -176,8 +176,8 @@ impedance — so it belongs to the material, not the geometry: it is a field of
176
176
 
177
177
  A fit in Kennedy–O'Hagan form treats an observation as $\tilde h = h(\theta) +
178
178
  \delta + \varepsilon$: the model prediction, a **discrepancy** and measurement
179
- noise. `MarginalLogLikelihood` scores it; see `pmrf.discrepancy_models` and
180
- `pmrf.likelihoods`.
179
+ noise. `pmrf.objectives.MarginalLogLikelihood` scores it; see
180
+ `pmrf.stats.GaussianProcess` and `pmrf.stats.GaussianLikelihood`.
181
181
 
182
182
  ### Event space and event block
183
183
 
@@ -32,13 +32,13 @@ For docs, we use sphinx. Simply run:
32
32
  In general, ParamRF follows a tiered API in order to isolate the JAX and solver logic. It is useful to understand the module split (and perhaps have a basic grasp on JAX PyTrees and perhaps the `Equinox` library) before continuing. A brief overview on the different modules and some JAX "gotchas" is given below.
33
33
 
34
34
  ### The Module Split
35
- Higher-level methods (fitting, optimization etc.) should be available to the user with minimal imports. However, these routines should build on top of "glue" helpers so that power users can pass additional arguments (such as custom evaluators in `pmrf.evaluators`) to customize the algorithm.
35
+ Higher-level methods (fitting, optimization etc.) should be available to the user with minimal imports. However, these routines should build on top of "glue" helpers so that power users can pass additional arguments (such as custom evaluators in `pmrf.objectives`) to customize the algorithm.
36
36
 
37
37
  * **Core Primitives** (`pmrf.Model`, `pmrf.Frequency`, `pmrf.Param`). These are the library's core primitives. They represent the foundational classes and functions that both users and library routines will interact with.
38
38
  * **Lower-level Routines** (`pmrf.math`, `pmrf.rf`). These functions implement simple, standard formulae. They should operate directly on JAX arrays or very simple PyTree structures.
39
39
  * **RF Models** (`pmrf.models`). These are the main, built-in RF models in the library. They have been separated into an deep organizational structure (e.g. lumped components, surrogates etc.). If a model's forward pass has many different possible implementations (for example, different models for a coaxial line, or different circuit solver algorithms) then a separate strategy class should be created alongside the model which implements some abstract interface (referred to as the "strategy" pattern, described below). See `pmrf.models.CoaxialLine` and `pmrf.models.Circuit` for simple and complex examples, respectively.
40
40
  * **General Algorithms** (`pmrf.optimize` and `pmrf.infer`). These are a combination of functional entry points and wrappers around external libraries. They refer to parametric, model-agnostic algorithms. These modules should be structured in a tiered manner to decouple the Equinox/JAX logic from the RF/model logic. Refer to `pmrf.optimize.base` and `pmrf.optimize.minimize` for a good example.
41
- * **Toolkits** (`pmrf.evaluators`, `pmrf.losses`, `pmrf.likelihoods`, `pmrf.discrepancy_models`, `pmrf.noise_models`, `pmrf.covariance_models`). These are the concrete "glue" components that provide users with a toolkit to mix-and-match together, mostly for power users.
41
+ * **Toolkits** (`pmrf.objectives`, `pmrf.stats`). These provide evaluators, losses, likelihoods, discrepancy models, noise models, and covariance kernels that users can mix and match.
42
42
  * **Routers** (`pmrf.fitting`) This is an example of a high-level convenience API specifically for fitting models to measured data. Functions here, like `fit`, `fit_minimize` or `fit_sample`, essentially act as "routers", converting different data formats (e.g. `skrf.Network`) and user specs into code that other modules in the library can understand.
43
43
 
44
44
  ### Abstract Classes and the Strategy Pattern
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramrf
3
- Version: 0.36.6
3
+ Version: 0.37.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
@@ -107,7 +107,7 @@ The code below demonstrate how to define and optimize an RLC model to satisfy a
107
107
  C = prf.Bounded(0.0, 100.0, scale=1e-12, name='C')
108
108
 
109
109
  model = Resistor(R) ** Inductor(L) ** Capacitor(C)
110
- goal = prf.evaluators.Goal('s11_db', '<', -20)
110
+ goal = prf.objectives.Goal('s11_db', '<', -20)
111
111
  passband = prf.Frequency(2, 5, 101, 'GHz')
112
112
 
113
113
  result = prf.optimize.minimize(goal, model, passband, solver=prf.optimize.NelderMead())
@@ -60,7 +60,7 @@ The code below demonstrate how to define and optimize an RLC model to satisfy a
60
60
  C = prf.Bounded(0.0, 100.0, scale=1e-12, name='C')
61
61
 
62
62
  model = Resistor(R) ** Inductor(L) ** Capacitor(C)
63
- goal = prf.evaluators.Goal('s11_db', '<', -20)
63
+ goal = prf.objectives.Goal('s11_db', '<', -20)
64
64
  passband = prf.Frequency(2, 5, 101, 'GHz')
65
65
 
66
66
  result = prf.optimize.minimize(goal, model, passband, solver=prf.optimize.NelderMead())
@@ -120,4 +120,4 @@ or using the BibTeX:
120
120
  eprint = {2510.15881},
121
121
  archivePrefix = {arXiv},
122
122
  primaryClass = {cs.OH},
123
- }
123
+ }
@@ -45,6 +45,9 @@ Main Modules
45
45
  pmrf.models
46
46
  pmrf.modules
47
47
  pmrf.materials
48
+ pmrf.parameters
49
+ pmrf.stats
50
+ pmrf.objectives
48
51
  pmrf.optimize
49
52
  pmrf.infer
50
53
  pmrf.fitting
@@ -56,18 +59,7 @@ Other Modules
56
59
  :toctree: generated/
57
60
  :recursive:
58
61
 
59
- pmrf.constraints
60
- pmrf.covariance_kernels
61
- pmrf.discrepancy_models
62
- pmrf.distributions
63
- pmrf.evaluators
64
- pmrf.problems
65
- pmrf.terms
66
- pmrf.likelihoods
67
- pmrf.losses
68
62
  pmrf.math
69
- pmrf.noise_models
70
- pmrf.parameters
71
63
  pmrf.rf
72
64
  pmrf.serialization
73
65
  pmrf.viz
@@ -1,7 +1,7 @@
1
1
  Core Primitives
2
2
  ===============
3
3
 
4
- The core primitives in ParamRF are the :class:`pmrf.Model`, :class:`pmrf.Frequency` and :class:`pmrf.Param` classes. Other classes, such as JAX arrays and :mod:`pmrf.evaluators`, help bring the rest of the library together.
4
+ The core primitives in ParamRF are the :class:`pmrf.Model`, :class:`pmrf.Frequency` and :class:`pmrf.Param` classes. Other classes, such as JAX arrays and :mod:`pmrf.objectives`, help bring the rest of the library together.
5
5
 
6
6
  The Model
7
7
  ~~~~~~~~~
@@ -26,16 +26,16 @@ Power users may want to have a look at the `Parax <https://github.com/gvcallen/p
26
26
  The Evaluator and other classes
27
27
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28
28
 
29
- :class:`~pmrf.evaluators.AbstractEvaluator` is an interface for a callable class that can be used to "evaluate" a model over frequency. Its output is a :class:`jnp.ndarray` (tensor or scalar). Evaluators can be used for extraction of model features, encapsulating loss/error/likelihood functions, and more. For example, to create a goal-oriented objective function for an optimization, the :class:`~pmrf.evaluators.Goal` evaluator can be used.
29
+ :class:`~pmrf.objectives.AbstractEvaluator` is an interface for a callable class that can be used to "evaluate" a model over frequency. Its output is a :class:`jnp.ndarray` (tensor or scalar). Evaluators can be used for extraction of model features, encapsulating loss/error/likelihood functions, and more. For example, to create a goal-oriented objective function for an optimization, the :class:`~pmrf.objectives.Goal` evaluator can be used.
30
30
 
31
- Evaluators are created automatically when fitting routines are called, such as :func:`~pmrf.optimize.minimize` or :func:`~pmrf.infer.sample`. For example, specifying ``'s21_db'`` as a fitting feature for :func:`~pmrf.fitting.fit` creates a :class:`~pmrf.evaluators.Feature` evaluator, whilst specifying a loss or likelihood function creates a :class:`~pmrf.evaluators.TargetLoss` or :class:`~pmrf.evaluators.MarginalLogLikelihood` evaluator respectively.
31
+ Evaluators are created automatically when fitting routines are called, such as :func:`~pmrf.optimize.minimize` or :func:`~pmrf.infer.sample`. For example, specifying ``'s21_db'`` as a fitting feature for :func:`~pmrf.fitting.fit` creates a :class:`~pmrf.objectives.Feature` evaluator, whilst specifying a loss or likelihood function creates a :class:`~pmrf.objectives.TargetLoss` or :class:`~pmrf.objectives.MarginalLogLikelihood` evaluator respectively.
32
32
 
33
33
  Since an evaluator takes frequency *as input*, the same evaluator can be re-used over different sweeps. For example, an evaluator can be fitted over a coarse sweep of measured data, and then plotted over a much finer one.
34
34
 
35
- When a model is solved, an evaluator is paired with the sweep it should be evaluated over using :class:`pmrf.terms.BoundEvaluator`, which optionally also accepts a relative weight. The result is a *term*, which is any callable that takes a model and returns a result. A :class:`pmrf.problems.SummedTerms` problem is then simply a model together with the terms to be summed over it. Where an evaluator takes a model and a frequency, and a term takes a model, a :class:`pmrf.problems.AbstractProblem` takes nothing further and returns the result directly.
35
+ When a model is solved, an evaluator is paired with the sweep it should be evaluated over using :class:`pmrf.objectives.BoundEvaluator`, which optionally also accepts a relative weight. The result is a *term*, which is any callable that takes a model and returns a result. A :class:`pmrf.objectives.SummedTerms` problem is then simply a model together with the terms to be summed over it. Where an evaluator takes a model and a frequency, and a term takes a model, a :class:`pmrf.objectives.AbstractProblem` takes nothing further and returns the result directly.
36
36
 
37
- Terms that do not require a frequency, such as a penalty on the model's parameters, can be written as a plain function of the model. The built-in terms inherit from :class:`pmrf.terms.AbstractTerm`, but this is a convenience and not a requirement. In most cases these classes do not need to be created manually, as :func:`~pmrf.optimize.minimize` and :func:`~pmrf.infer.sample` create them automatically.
37
+ Terms that do not require a frequency, such as a penalty on the model's parameters, can be written as a plain function of the model. The built-in terms inherit from :class:`pmrf.objectives.AbstractTerm`, but this is a convenience and not a requirement. In most cases these classes do not need to be created manually, as :func:`~pmrf.optimize.minimize` and :func:`~pmrf.infer.sample` create them automatically.
38
38
 
39
- Priors are parameter metadata, and are stripped when a tree is unwrapped for a solver, so they cannot be read from inside an evaluator or a term. Instead, :class:`pmrf.problems.PriorPenalized` extracts them once when it is constructed and evaluates them against the parameter values on each call. This is what separates a maximum a posteriori estimate from a maximum likelihood one, and it is selected automatically when `inference` is 'bayesian' in :func:`~pmrf.fitting.fit`.
39
+ Priors are parameter metadata, and are stripped when a tree is unwrapped for a solver, so they cannot be read from inside an evaluator or a term. Instead, :class:`pmrf.objectives.PriorPenalized` extracts them once when it is constructed and evaluates them against the parameter values on each call. This is what separates a maximum a posteriori estimate from a maximum likelihood one, and it is selected automatically when `inference` is 'bayesian' in :func:`~pmrf.fitting.fit`.
40
40
 
41
- Other core class interfaces include those in :class:`~pmrf.losses`, :class:`~pmrf.likelihoods`, :class:`~pmrf.discrepancy_models` and :class:`~pmrf.noise_models`. These help glue the rest of the library together, as well as enable more advanced features such as hyperparameter-based optimization and Gaussian process discrepancy modeling. See the :doc:`../tutorials/index` section for more information.
41
+ Other interfaces include :class:`~pmrf.objectives.AbstractLoss`, :class:`~pmrf.stats.AbstractLikelihood`, :class:`~pmrf.stats.AbstractDiscrepancyModel` and :class:`~pmrf.stats.AbstractNoiseModel`. See the :doc:`../tutorials/index` section for more examples.
@@ -17,11 +17,11 @@ An objective can also be paired with its own frequency sweep. This allows a sing
17
17
  .. code-block:: python
18
18
 
19
19
  result = minimize([
20
- (prf.evaluators.Goal('s11_db', '<', -20), prf.Frequency(50, 130, 101, 'MHz')),
21
- (prf.evaluators.Goal('s21_db', '>', -1), prf.Frequency(10, 500, 401, 'MHz')),
20
+ (prf.objectives.Goal('s11_db', '<', -20), prf.Frequency(50, 130, 101, 'MHz')),
21
+ (prf.objectives.Goal('s21_db', '>', -1), prf.Frequency(10, 500, 401, 'MHz')),
22
22
  ], model)
23
23
 
24
- To weight the objectives against one another, the pairing can be created explicitly using :class:`pmrf.terms.BoundEvaluator`. Any callable that accepts only a model, such as a penalty on the parameters that requires no frequency, can also be summed in directly:
24
+ To weight the objectives against one another, the pairing can be created explicitly using :class:`pmrf.objectives.BoundEvaluator`. Any callable that accepts only a model, such as a penalty on the parameters that requires no frequency, can also be summed in directly:
25
25
 
26
26
  .. code-block:: python
27
27
 
@@ -54,7 +54,7 @@ The code below demonstrates this by extending the previous class, while constrai
54
54
  :include-source:
55
55
 
56
56
  # <previous imports>
57
- from pmrf.constraints import Positive
57
+ from pmrf.parameters.constraints import Positive
58
58
 
59
59
  class Capacitor(Capacitor):
60
60
  C: prf.Param = prf.param(constraint=Positive(), as_free=True, scale=1e-12)
@@ -1,12 +1,12 @@
1
1
  Discrepancy Prediction
2
2
  ======================
3
3
 
4
- A fit with a Gaussian-process discrepancy learns how the model differs from the data, not just the model parameters. That discrepancy can be predicted at frequencies the fit never saw, with its uncertainty. In this example we fit the S11 of a 10 m coaxial line with a GP discrepancy, then predict the discrepancy off the fit grid.
4
+ A fitted Gaussian-process discrepancy can be predicted at new frequencies, with its uncertainty. Here we fit the S11 of a coaxial line and predict its discrepancy beyond the fit band.
5
5
 
6
6
  Fitting with a Discrepancy
7
7
  ~~~~~~~~~~~~~~~~~~~~~~~~~~
8
8
 
9
- The measured S11 is a coaxial line plus a slow ripple that the model cannot produce, and a little measurement noise. We fit the dielectric constant, with a :class:`~pmrf.discrepancy_models.GaussianProcess` to absorb the ripple. Its kernel's length scale is in the fit frequency's unit, here MHz:
9
+ We add a slow ripple and measurement noise to the line's S11, then fit the dielectric constant with a :class:`~pmrf.stats.GaussianProcess` for the discrepancy. The kernel length scale uses the fit frequency's unit, MHz:
10
10
 
11
11
  .. plot::
12
12
  :context: reset
@@ -18,9 +18,7 @@ The measured S11 is a coaxial line plus a slow ripple that the model cannot prod
18
18
  from pmrf.models import CoaxialLine
19
19
  from pmrf.materials import BulkConductor, ConstantDielectric
20
20
  from pmrf.fitting import fit
21
- from pmrf.likelihoods import GaussianLikelihood
22
- from pmrf.discrepancy_models import GaussianProcess
23
- from pmrf.covariance_kernels import Matern52Kernel
21
+ from pmrf.stats import GaussianLikelihood, GaussianProcess, Matern52Kernel
24
22
 
25
23
  def coax(ep_r):
26
24
  return CoaxialLine(
@@ -48,7 +46,7 @@ The measured S11 is a coaxial line plus a slow ripple that the model cannot prod
48
46
  Predicting the Discrepancy
49
47
  ~~~~~~~~~~~~~~~~~~~~~~~~~~
50
48
 
51
- The fitted :class:`~pmrf.evaluators.MarginalLogLikelihood`, with its optimized GP hyperparameters and noise, is the one term of the fit's objective. :meth:`~pmrf.evaluators.MarginalLogLikelihood.predict_discrepancy` conditions the GP on the fit's residuals and returns the distribution of the discrepancy at new frequencies. Here they extend past the fit band and are given in GHz; they are converted to the fit's unit first.
49
+ :meth:`~pmrf.objectives.MarginalLogLikelihood.predict_discrepancy` uses the fitted model and residuals to predict the discrepancy. The new frequency grid extends beyond the fit band and uses GHz; the method handles the unit conversion.
52
50
 
53
51
  .. plot::
54
52
  :context:
@@ -74,4 +72,4 @@ The fitted :class:`~pmrf.evaluators.MarginalLogLikelihood`, with its optimized G
74
72
  axes[0].legend()
75
73
  axes[1].set_xlabel('Frequency (MHz)')
76
74
 
77
- The prediction is in event space: one block for the real part of S11 and one for the imaginary part, with frequency last. It is of the discrepancy alone, and excludes measurement noise. Inside the fit band it follows the ripple closely; beyond it, the mean relaxes towards zero and the uncertainty grows back to the GP's prior.
75
+ The prediction has separate real and imaginary S11 blocks, with frequency last. It excludes measurement noise. Beyond the fit band, the mean approaches zero and uncertainty grows.
@@ -9,10 +9,9 @@ This chapter includes some basic examples to demonstrate ParamRF's core features
9
9
  cascading_and_terminating
10
10
  circuit_models
11
11
  model_optimization
12
- discrepancy_prediction
13
- port_discrepancy
14
12
  derivatives_and_sweeps
15
13
  parameter_naming_and_model_manipulation
16
14
  custom_models
17
15
  multiple_models_one_parameter_set
18
- shared_substrates
16
+ shared_modules
17
+ discrepancy_prediction
@@ -26,13 +26,13 @@ It is best practice to apply a scaling factor to our values in order to keep the
26
26
  Running the Optimizer
27
27
  ~~~~~~~~~~~~~~~~~~~~~
28
28
 
29
- Next, we define our design goals. In this case, we want to ensure good matching (low reflection) across our passband. We can use the :class:`~pmrf.evaluators.Goal` evaluator and pass it to the :func:`~pmrf.optimize.minimize` function alongside our frequency range:
29
+ Next, we define our design goals. In this case, we want to ensure good matching (low reflection) across our passband. We can use the :class:`~pmrf.objectives.Goal` evaluator and pass it to the :func:`~pmrf.optimize.minimize` function alongside our frequency range:
30
30
 
31
31
  .. plot::
32
32
  :context:
33
33
  :include-source:
34
34
 
35
- from pmrf.evaluators import Goal
35
+ from pmrf.objectives import Goal
36
36
  from pmrf.optimize import minimize, ScipyMinimize
37
37
 
38
38
  match_goal = Goal('s11_db', '<', -20)
@@ -71,6 +71,6 @@ For more complex designs, the :func:`~pmrf.optimize.minimize` function can accep
71
71
  (Goal('s21_db', '<', -40), stopband),
72
72
  ], lpf, solver=ScipyMinimize(method='L-BFGS-B'))
73
73
 
74
- See the :doc:`/core_concepts/optimization_and_inference` page for how to weight such goals against one another. For even more advanced optimization, custom losses can be specified, either using the built-in losses in :mod:`~pmrf.losses`; using a custom callable; or by creating a custom :class:`~pmrf.evaluators.AbstractEvaluator`. The last example is the most powerful, allowing the specification of arbitrary, tunable hyper-parameters.
74
+ See the :doc:`/core_concepts/optimization_and_inference` page for how to weight such goals against one another. For even more advanced optimization, custom losses can be specified, either using the built-in losses in :mod:`~pmrf.objectives`; using a custom callable; or by creating a custom :class:`~pmrf.objectives.AbstractEvaluator`. The last example is the most powerful, allowing the specification of arbitrary, tunable hyper-parameters.
75
75
 
76
76
  Note that ParamRF also provides convenience functions for fitting models directly to data in :func:`~pmrf.fitting`. See the tutorial for a detailed guide.
@@ -0,0 +1,30 @@
1
+ Sharing a Module Across Models
2
+ ==============================
3
+
4
+ A model normally owns its modules and their parameters. To share one module across
5
+ several models, store it on an :class:`pmrf.models.AbstractBuilder` and pass it to
6
+ each model in ``build``. This board shares one substrate between two traces.
7
+
8
+ .. jupyter-execute::
9
+
10
+ import pmrf as prf
11
+ from pmrf.materials import ConstantDielectric, Substrate
12
+ from pmrf.models import AbstractBuilder, MicrostripLine
13
+
14
+ class Board(AbstractBuilder):
15
+ substrate: Substrate
16
+ w1: prf.Param
17
+ w2: prf.Param
18
+
19
+ def build(self):
20
+ return (
21
+ MicrostripLine(w=self.w1, substrate=self.substrate, length=0.1)
22
+ ** MicrostripLine(w=self.w2, substrate=self.substrate, length=0.2)
23
+ )
24
+
25
+ board = Board(
26
+ substrate=Substrate(h=1.6e-3, dielectric=ConstantDielectric(ep_r=4.3, tand=0.02)),
27
+ w1=1.0e-3,
28
+ w2=2.0e-3,
29
+ )
30
+ list(prf.params(board))
@@ -28,7 +28,7 @@ The script below builds the same circuit in ``scikit-rf`` and ParamRF once, then
28
28
  GlobalMNACircuitSolver,
29
29
  )
30
30
  from pmrf.parameters import Bounded
31
- from pmrf.evaluators import Goal
31
+ from pmrf.objectives import Goal
32
32
  from pmrf.optimize import minimize as pmrf_minimize, ScipyMinimize
33
33
 
34
34
  c = scipy.constants.c
@@ -0,0 +1,317 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Fitting and transferring discrepancy\n",
8
+ "\n",
9
+ "A discrepancy describes the part of a measured response that a physical model misses. This tutorial fits a lossy coax with a small conductor error, predicts the correction with its uncertainty, and carries it to a new line length. It then shows how a port discrepancy can carry a joint parameter and correction prediction into a terminated circuit.\n",
10
+ "\n",
11
+ "The [discrepancy prediction example](../examples/discrepancy_prediction.rst) is the short introduction. The code here uses small synthetic data sets so every result can be checked against a known line."
12
+ ],
13
+ "id": "discrepancy-01"
14
+ },
15
+ {
16
+ "cell_type": "markdown",
17
+ "metadata": {},
18
+ "source": [
19
+ "## A reference line and a shorter target\n",
20
+ "\n",
21
+ "The reference line is 30 cm long; the target is 15 cm. The nominal line has 10% excess conductor loss. A port correction belongs to the reference response, while an internal correction changes characteristic impedance, attenuation, and phase per unit length. That distinction matters when the line length changes."
22
+ ],
23
+ "id": "discrepancy-02"
24
+ },
25
+ {
26
+ "cell_type": "code",
27
+ "execution_count": null,
28
+ "metadata": {},
29
+ "outputs": [],
30
+ "source": [
31
+ "from pathlib import Path\n",
32
+ "import sys\n",
33
+ "import jax\n",
34
+ "import jax.numpy as jnp\n",
35
+ "import matplotlib.pyplot as plt\n",
36
+ "import numpy as np\n",
37
+ "from scipy.optimize import minimize as scipy_minimize\n",
38
+ "import pmrf as prf\n",
39
+ "from pmrf.materials import BulkConductor, ConstantDielectric\n",
40
+ "from pmrf.models import (\n",
41
+ " CoaxialLine, GridLineDiscrepancy, GridPortDiscrepancy, LineCorrected,\n",
42
+ " Load, PortCorrected, line_internal_features, project_line_basis_joint,\n",
43
+ " reference_line_features,\n",
44
+ ")\n",
45
+ "from pmrf.objectives import MarginalLogLikelihood\n",
46
+ "from pmrf.optimize import ScipyMinimize, minimize\n",
47
+ "from pmrf.stats import (\n",
48
+ " GaussianLikelihood, GaussianProcess, Matern52Kernel, RBFKernel, posterior_covariance,\n",
49
+ ")\n",
50
+ "\n",
51
+ "tutorial_dir = Path.cwd()\n",
52
+ "if not (tutorial_dir / \"line_internal_discrepancy.py\").exists():\n",
53
+ " tutorial_dir = Path(\"docs/tutorials\")\n",
54
+ "sys.path.insert(0, str(tutorial_dir.resolve()))\n",
55
+ "from line_internal_discrepancy import (\n",
56
+ " MODEL_SIGMA, TRUTH_SIGMA, _basis, compare_transfer,\n",
57
+ " exact_values, frequency, line,\n",
58
+ ")\n",
59
+ "from port_discrepancy import ReciprocalEventTransform, reciprocal_predictor\n",
60
+ "\n",
61
+ "f = frequency()\n",
62
+ "comparison = compare_transfer()\n",
63
+ "for name, errors in comparison.items():\n",
64
+ " print(f\"{name}: RMS S21 error = {errors['rms_s21']:.4g}, eta bias = {errors['eta_bias']:.4g}\")"
65
+ ],
66
+ "id": "discrepancy-03"
67
+ },
68
+ {
69
+ "cell_type": "markdown",
70
+ "metadata": {},
71
+ "source": [
72
+ "The internal correction follows the shorter line's electrical length. The port correction uses the reference line's S-parameter error as if it belonged to the shorter line."
73
+ ],
74
+ "id": "discrepancy-04"
75
+ },
76
+ {
77
+ "cell_type": "markdown",
78
+ "metadata": {},
79
+ "source": [
80
+ "## Learn an internal correction\n",
81
+ "\n",
82
+ "Here the reference measurement supplies characteristic impedance $Z_c$ and propagation constant $\\gamma$. `reference_line_features` converts them to the four log-ratio channels used by `GridLineDiscrepancy`: real and imaginary $\\log Z_c$, log attenuation, and log phase constant. The likelihood variance is specified in this transformed event space.\n",
83
+ "\n",
84
+ "The nominal model has a free conductor parameter. `predict_joint` returns one Gaussian over that parameter and the correction grid, preserving their covariance."
85
+ ],
86
+ "id": "discrepancy-05"
87
+ },
88
+ {
89
+ "cell_type": "code",
90
+ "execution_count": null,
91
+ "metadata": {},
92
+ "outputs": [],
93
+ "source": [
94
+ "reference = line(0.30, TRUTH_SIGMA)\n",
95
+ "zc, gamma_length = reference.zc_and_gammaL(f)\n",
96
+ "observed = reference_line_features(zc, gamma_length / 0.30)\n",
97
+ "nominal = line(0.30, MODEL_SIGMA, free_sigma=True)\n",
98
+ "reference_likelihood = MarginalLogLikelihood(\n",
99
+ " predictor=line_internal_features,\n",
100
+ " observed=observed,\n",
101
+ " likelihood=GaussianLikelihood(1e-10),\n",
102
+ " discrepancy=GaussianProcess(RBFKernel(0.5) * 0.1**2, jitter=1e-12),\n",
103
+ ")\n",
104
+ "names, joint = reference_likelihood.predict_joint(nominal, f, f)\n",
105
+ "print(\"Joint dimensions:\", joint.mean().shape[0], \"parameter names:\", names)"
106
+ ],
107
+ "id": "discrepancy-06"
108
+ },
109
+ {
110
+ "cell_type": "markdown",
111
+ "metadata": {},
112
+ "source": [
113
+ "The same prediction can be attached to a shorter line. The joint prior keeps the conductor parameter correlated with the discrepancy values. `truncate='unnormalised'` respects the conductor's validity range for MAP work; it is unsuitable for sampling or evidence calculations."
114
+ ],
115
+ "id": "discrepancy-07"
116
+ },
117
+ {
118
+ "cell_type": "code",
119
+ "execution_count": null,
120
+ "metadata": {},
121
+ "outputs": [],
122
+ "source": [
123
+ "carrier = GridLineDiscrepancy.from_prediction(f, joint, joint=True)\n",
124
+ "short_line = LineCorrected(line(0.15, MODEL_SIGMA, free_sigma=True), carrier)\n",
125
+ "short_line = prf.prior(\n",
126
+ " short_line, [*names, \"discrepancy.values\"], joint,\n",
127
+ " truncate=\"unnormalised\",\n",
128
+ ")\n",
129
+ "truth_short = line(0.15, TRUTH_SIGMA)\n",
130
+ "rms_s21 = np.sqrt(np.mean(np.abs(np.asarray(short_line.s(f) - truth_short.s(f))[:, 1, 0])**2))\n",
131
+ "print(\"Transferred RMS S21 error:\", float(rms_s21))"
132
+ ],
133
+ "id": "discrepancy-08"
134
+ },
135
+ {
136
+ "cell_type": "markdown",
137
+ "metadata": {},
138
+ "source": [
139
+ "The joint mean contains the conductor parameter first, then four correction channels. Its diagonal gives marginal uncertainty in each channel; the off-diagonal entries still matter when the correction is used with the conductor parameter."
140
+ ],
141
+ "id": "discrepancy-09"
142
+ },
143
+ {
144
+ "cell_type": "code",
145
+ "execution_count": null,
146
+ "metadata": {},
147
+ "outputs": [],
148
+ "source": [
149
+ "mean = np.asarray(joint.mean())[1:].reshape(2, 2, f.npoints)\n",
150
+ "std = np.sqrt(np.diag(np.asarray(joint.covariance()))[1:]).reshape(2, 2, f.npoints)\n",
151
+ "truth = np.asarray(exact_values(f))\n",
152
+ "labels = (\"log Zc real\", \"log Zc imaginary\", \"log attenuation\", \"log phase\")\n",
153
+ "fig, axes = plt.subplots(2, 2, figsize=(10, 6), sharex=True)\n",
154
+ "for axis, label, predicted, sigma, actual in zip(axes.flat, labels, mean.reshape(4, -1), std.reshape(4, -1), truth.reshape(4, -1)):\n",
155
+ " axis.plot(f.f_scaled, actual, label=\"injected\")\n",
156
+ " axis.plot(f.f_scaled, predicted, label=\"predicted\")\n",
157
+ " axis.fill_between(f.f_scaled, predicted - 2*sigma, predicted + 2*sigma, alpha=0.2)\n",
158
+ " axis.set_title(label)\n",
159
+ "axes[0, 0].legend()\n",
160
+ "fig.tight_layout()"
161
+ ],
162
+ "id": "discrepancy-10"
163
+ },
164
+ {
165
+ "cell_type": "markdown",
166
+ "metadata": {},
167
+ "source": [
168
+ "## When only S-parameters are measured\n",
169
+ "\n",
170
+ "The preceding route uses $Z_c$ and $\\gamma$. If the reference only provides complex S-parameters, represent the internal correction with basis coefficients and fit them through the line response. The [supporting script](line_internal_discrepancy.py) defines the basis from an RBF spectral density; the fit and projection are shown below."
171
+ ],
172
+ "id": "discrepancy-11"
173
+ },
174
+ {
175
+ "cell_type": "code",
176
+ "execution_count": null,
177
+ "metadata": {},
178
+ "outputs": [],
179
+ "source": [
180
+ "basis = _basis(f)\n",
181
+ "nominal_s = LineCorrected(line(0.30, MODEL_SIGMA), basis)\n",
182
+ "observed_s = line(0.30, TRUTH_SIGMA).s(f)\n",
183
+ "s_likelihood = MarginalLogLikelihood(\n",
184
+ " predictor=lambda model, grid: model.s(grid),\n",
185
+ " observed=observed_s,\n",
186
+ " likelihood=GaussianLikelihood(1e-8),\n",
187
+ ")\n",
188
+ "objective = lambda model: -s_likelihood(model, f) - prf.log_prior(model)\n",
189
+ "fitted_s = minimize(objective, nominal_s, solver=ScipyMinimize(method=\"BFGS\"), max_iter=400).model\n",
190
+ "fitted_basis = prf.update(\n",
191
+ " basis, \"coefficients\", value=prf.values(fitted_s)[\"discrepancy.coefficients\"]\n",
192
+ ")\n",
193
+ "linearization = s_likelihood.linearize(fitted_s, f)\n",
194
+ "covariance = posterior_covariance([linearization], fitted_s)\n",
195
+ "names_s, joint_s = project_line_basis_joint(\n",
196
+ " fitted_s, fitted_basis, linearization, covariance, f\n",
197
+ ")\n",
198
+ "carrier_s = GridLineDiscrepancy.from_prediction(f, joint_s, joint=True)\n",
199
+ "short_s = LineCorrected(line(0.15, MODEL_SIGMA), carrier_s)\n",
200
+ "rms_s = np.sqrt(np.mean(np.abs(np.asarray(short_s.s(f) - truth_short.s(f))[:, 1, 0])**2))\n",
201
+ "mean_s = np.asarray(joint_s.mean()).reshape(2, 2, f.npoints)\n",
202
+ "std_s = np.sqrt(np.diag(np.asarray(joint_s.covariance()))).reshape(2, 2, f.npoints)\n",
203
+ "coverage = np.mean(np.abs(np.asarray(exact_values(f)) - mean_s) <= 2 * std_s)\n",
204
+ "print(\"Transferred RMS S21 error:\", float(rms_s))\n",
205
+ "print(\"Injected values within mean ± 2σ:\", float(coverage))"
206
+ ],
207
+ "id": "discrepancy-12"
208
+ },
209
+ {
210
+ "cell_type": "markdown",
211
+ "metadata": {},
212
+ "source": [
213
+ "## Port discrepancy in a later circuit\n",
214
+ "\n",
215
+ "A port correction applies when the fitted component stays the same and its surrounding circuit changes. Here the reference fit estimates a bounded coax length and a reciprocal port discrepancy. The [supporting script](port_discrepancy.py) defines the event transform used for symmetric transmission and contains independent covariance checks. We use that transform below, then carry the joint prediction into a terminated circuit."
216
+ ],
217
+ "id": "discrepancy-13"
218
+ },
219
+ {
220
+ "cell_type": "code",
221
+ "execution_count": null,
222
+ "metadata": {},
223
+ "outputs": [],
224
+ "source": [
225
+ "def cable(length):\n",
226
+ " return CoaxialLine(\n",
227
+ " length=length,\n",
228
+ " d_in=prf.Fixed(1.12e-3), d_out=prf.Fixed(3.2e-3),\n",
229
+ " dielectric=ConstantDielectric(ep_r=prf.Fixed(1.384), tand=prf.Fixed(0.001)),\n",
230
+ " conductor=BulkConductor(sigma=prf.Fixed(1 / 1.6e-8)),\n",
231
+ " )\n",
232
+ "\n",
233
+ "reference_f = prf.Frequency(100, 500, 12, \"MHz\")\n",
234
+ "transfer_f = prf.Frequency(120, 480, 6, \"MHz\")\n",
235
+ "true_cable = cable(prf.Fixed(0.1))\n",
236
+ "initial_cable = cable(prf.Bounded(0.05, 0.15, value=0.095))\n",
237
+ "reference_port = MarginalLogLikelihood(\n",
238
+ " predictor=reciprocal_predictor,\n",
239
+ " observed=reciprocal_predictor(true_cable, reference_f),\n",
240
+ " likelihood=GaussianLikelihood(jnp.full((3, 2, reference_f.npoints), 1e-8)),\n",
241
+ " discrepancy=GaussianProcess(Matern52Kernel(80.0) * 1e-6, jitter=1e-12),\n",
242
+ " event_transform=ReciprocalEventTransform,\n",
243
+ ")\n",
244
+ "\n",
245
+ "def port_loss(length):\n",
246
+ " return -reference_port(prf.update(initial_cable, {\"length\": length}), reference_f)\n",
247
+ "\n",
248
+ "value_gradient = jax.jit(jax.value_and_grad(port_loss))\n",
249
+ "fit_result = scipy_minimize(\n",
250
+ " lambda x: tuple(np.asarray(v) for v in value_gradient(jnp.asarray(x))),\n",
251
+ " np.array([0.095]), jac=True, method=\"L-BFGS-B\", bounds=[(0.05, 0.15)],\n",
252
+ " options={\"maxiter\": 1000, \"gtol\": 1e-10, \"ftol\": 1e-14},\n",
253
+ ")\n",
254
+ "assert fit_result.success\n",
255
+ "fitted_cable = prf.update(initial_cable, {\"length\": jnp.asarray(fit_result.x[0])})\n",
256
+ "port_names, port_joint = reference_port.predict_joint(fitted_cable, reference_f, transfer_f)\n",
257
+ "print(\"Fitted length:\", float(prf.values(fitted_cable)[\"length\"]))"
258
+ ],
259
+ "id": "discrepancy-14"
260
+ },
261
+ {
262
+ "cell_type": "code",
263
+ "execution_count": null,
264
+ "metadata": {},
265
+ "outputs": [],
266
+ "source": [
267
+ "port_mean = port_joint.mean()[1:].reshape(3, 2, transfer_f.npoints)\n",
268
+ "corrected_cable = PortCorrected(\n",
269
+ " fitted_cable,\n",
270
+ " GridPortDiscrepancy(prf.Unconstrained(port_mean), transfer_f, (\"11\", \"22\", \"s21\")),\n",
271
+ ")\n",
272
+ "corrected_cable = prf.prior(\n",
273
+ " corrected_cable, [*port_names, \"discrepancy.values\"], port_joint,\n",
274
+ " truncate=\"unnormalised\",\n",
275
+ ")\n",
276
+ "load = Load(gamma=(75.0 - 50.0) / (75.0 + 50.0), z0=50.0)\n",
277
+ "transfer_circuit = corrected_cable.terminated(load)\n",
278
+ "observed_reflection = true_cable.terminated(load).s(transfer_f, z0=50.0)[:, 0, 0]\n",
279
+ "transfer_likelihood = MarginalLogLikelihood(\n",
280
+ " predictor=lambda model, grid: model.s(grid, z0=50.0)[:, 0, 0],\n",
281
+ " observed=observed_reflection,\n",
282
+ " likelihood=GaussianLikelihood(1e-6),\n",
283
+ ")\n",
284
+ "transfer_linearization = transfer_likelihood.linearize(\n",
285
+ " transfer_circuit, transfer_f, space=\"declared\"\n",
286
+ ")\n",
287
+ "transfer_covariance = posterior_covariance(\n",
288
+ " [transfer_linearization], transfer_circuit, space=\"declared\"\n",
289
+ ")\n",
290
+ "print(\"Joint dimension:\", port_joint.mean().shape[0])\n",
291
+ "print(\"Transferred log prior:\", float(prf.log_prior(transfer_circuit, space=\"declared\")))\n",
292
+ "print(\"Posterior variance, first coordinate:\", float(transfer_covariance[0, 0]))"
293
+ ],
294
+ "id": "discrepancy-15"
295
+ },
296
+ {
297
+ "cell_type": "markdown",
298
+ "metadata": {},
299
+ "source": [
300
+ "The carrier follows what stays physically common between fits: use an internal line correction across lengths, or a port correction when moving the same component into another circuit. The joint distribution retains parameter–discrepancy covariance in each later calculation. The [port script](port_discrepancy.py) compares the final covariance with a NumPy Kalman update and checks the transferred prior's precision."
301
+ ],
302
+ "id": "discrepancy-16"
303
+ }
304
+ ],
305
+ "metadata": {
306
+ "kernelspec": {
307
+ "display_name": "Python 3",
308
+ "language": "python",
309
+ "name": "python3"
310
+ },
311
+ "language_info": {
312
+ "name": "python"
313
+ }
314
+ },
315
+ "nbformat": 4,
316
+ "nbformat_minor": 5
317
+ }
@@ -7,4 +7,5 @@ This section includes more detailed tutorials that can be followed step-by-step
7
7
  :maxdepth: 2
8
8
 
9
9
  1_cable_fitting.ipynb
10
- 2_chip_inductor_fitting.ipynb
10
+ 2_chip_inductor_fitting.ipynb
11
+ 3_discrepancy_transfer.ipynb