paramrf 0.34.4__tar.gz → 0.35.2__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.
- paramrf-0.35.2/.github/workflows/tests.yml +34 -0
- paramrf-0.35.2/CHANGELOG.md +126 -0
- paramrf-0.35.2/CITATION.cff +14 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/CONTEXT.md +60 -5
- {paramrf-0.34.4 → paramrf-0.35.2}/CONTRIBUTING.md +6 -13
- {paramrf-0.34.4/paramrf.egg-info → paramrf-0.35.2}/PKG-INFO +3 -3
- {paramrf-0.34.4 → paramrf-0.35.2}/README.rst +1 -1
- paramrf-0.35.2/docs/adr/0002-parameter-api.md +255 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/api/index.rst +13 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/core_concepts/core_primitives.rst +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/core_concepts/index.rst +1 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/core_concepts/jax_overview.rst +2 -2
- paramrf-0.35.2/docs/core_concepts/parameter_names.rst +48 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/custom_models.rst +2 -2
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/derivatives_and_sweeps.rst +28 -16
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/model_optimization.rst +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/multiple_models_one_parameter_set.rst +2 -2
- paramrf-0.35.2/docs/examples/parameter_naming_and_model_manipulation.rst +151 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/shared_substrates.rst +2 -2
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/tutorials/1_cable_fitting.ipynb +6 -13
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/tutorials/2_chip_inductor_fitting.ipynb +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/paper/paper.bib +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2/paramrf.egg-info}/PKG-INFO +3 -3
- {paramrf-0.34.4 → paramrf-0.35.2}/paramrf.egg-info/SOURCES.txt +15 -2
- {paramrf-0.34.4 → paramrf-0.35.2}/paramrf.egg-info/requires.txt +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/__init__.py +11 -3
- paramrf-0.35.2/pmrf/_solver_view.py +125 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/evaluators.py +5 -17
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/base.py +71 -95
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/substrate.py +7 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/delegated.py +4 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/static.py +86 -58
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/base.py +20 -72
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/nonuniform.py +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/circuit.py +56 -12
- paramrf-0.35.2/pmrf/modules/base.py +134 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/modules/wrapped.py +1 -18
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/base.py +35 -69
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/minimize.py +3 -4
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/solvers/jaxopt.py +3 -3
- paramrf-0.35.2/pmrf/parameters.py +1618 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/problems.py +12 -6
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/serialization.py +77 -29
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/__init__.py +1 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/transforms.py +53 -14
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/tree.py +159 -56
- {paramrf-0.34.4 → paramrf-0.35.2}/pyproject.toml +2 -2
- paramrf-0.35.2/scripts/install-test-deps.sh +22 -0
- paramrf-0.35.2/tests/_jit.py +27 -0
- paramrf-0.35.2/tests/conftest.py +19 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_dc_limits.py +2 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_evaluators.py +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_fitting_routers.py +4 -2
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_fitting_targets.py +11 -7
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_map_priors.py +12 -6
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_materials/test_substrate.py +3 -2
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_model.py +28 -5
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_adapters.py +106 -2
- paramrf-0.35.2/tests/test_models/test_circuit_port_order.py +168 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_module.py +14 -9
- paramrf-0.35.2/tests/test_naming.py +421 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_optimize_base.py +16 -20
- paramrf-0.35.2/tests/test_parameters.py +203 -0
- paramrf-0.35.2/tests/test_parameters_by_name.py +364 -0
- paramrf-0.35.2/tests/test_raw_space_solving.py +318 -0
- paramrf-0.35.2/tests/test_serialization.py +73 -0
- paramrf-0.35.2/tests/test_structural_updates.py +235 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_transforms.py +96 -0
- paramrf-0.35.2/tests/test_utils/test_tree.py +43 -0
- paramrf-0.34.4/.github/workflows/tests.yml +0 -44
- paramrf-0.34.4/CHANGELOG.md +0 -11
- paramrf-0.34.4/docs/examples/parameter_naming_and_model_manipulation.rst +0 -82
- paramrf-0.34.4/pmrf/modules/base.py +0 -231
- paramrf-0.34.4/pmrf/parameters.py +0 -945
- paramrf-0.34.4/pmrf/utils/optix.py +0 -313
- paramrf-0.34.4/tests/test_naming.py +0 -146
- {paramrf-0.34.4 → paramrf-0.35.2}/.github/workflows/docs.yml +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/.github/workflows/draft-pdf.yml +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/.github/workflows/publish.yml +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/.gitignore +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/AGENTS.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/CLAUDE.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/LICENSE +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/NOTICE +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/assets/logo.png +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/Makefile +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/_static/custom.css +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/_templates/autosummary/class.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/_templates/autosummary/function.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/_templates/autosummary/module.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/adr/0001-line-modelling-architecture.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/agents/domain.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/agents/issue-tracker.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/agents/triage-labels.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/conf.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/core_concepts/optimization_and_inference.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/cascading_and_terminating.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/circuit_clc.png +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/circuit_models.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/examples/index.rst +1 -1
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/index.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/license.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/make.bat +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/research/conductor-loss-alternatives.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/research/holloway1994.pdf +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/research/microstrip-loss-conventions.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/research/precision-coax-microstrip-10-500mhz.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/skrf_comparison/index.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/skrf_comparison/overview.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/skrf_comparison/performance.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/tutorials/data/CBN-1.5FT-SMSM.s2p +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/tutorials/data/on-chip-inductor.s2p +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/docs/tutorials/index.rst +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/paper/paper.md +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/paper/rlc.png +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/paramrf.egg-info/dependency_links.txt +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/paramrf.egg-info/top_level.txt +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/bijectors.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/constraints.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/covariance_kernels.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/discrepancy_models.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/distributions.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/minimize.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/result.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/routers.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/sample.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/fitting/targets.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/frequency.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/result.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/sample.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/solvers/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/solvers/blackjax.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/infer/solvers/polychord.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/likelihoods.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/losses.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/conductor.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/dielectric.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/properties.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/roughness.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/materials/surface_impedance.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/aggregations.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/bessel.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/conversions.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/losses.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/math/misc.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/base.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/bridge.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/callable.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/adapters/wrapped.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/ideal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/base.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/coaxial.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/empirical.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/ideal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/microstrip.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/nodal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/planar.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lines/stripline.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/lumped.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/components/sections.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/cascade.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/base.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/solvers/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/solvers/nodal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/circuit/solvers/scattering.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/interconnected/terminated.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/nodal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/topological.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/composite/transformed.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/surrogates/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/surrogates/expansion.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/models/surrogates/rational.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/modules/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/network_collection.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/noise_models.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/result.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/solvers/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/solvers/optimistix.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/optimize/solvers/scipy.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/rf/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/rf/conversions.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/rf/mna.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/terms.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/types.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/array.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/debug.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/network.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/random.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/rf.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/utils/type.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/viz/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/pmrf/viz/plots.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/setup.cfg +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/__init__.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/_dependency_checks.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/data/10m_cable.s2p +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_autodiff.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_conversions.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_covariance_kernels.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_fitting_minimize.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_fitting_sample.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_frequency.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_infer_base.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_infer_sample.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_materials/test_conductor.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_materials/test_dielectric.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_materials/test_serialization.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_materials/test_surface_impedance.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_math/test_bessel.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_circuit_nodal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_circuit_scattering.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_current_distribution.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_interconnected.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_lines.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_lines_skrf_matrix.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_lumped.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_nodal.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_sections.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_transformed.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_models/test_transformers.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_optimize_minimize.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_terms.py +0 -0
- {paramrf-0.34.4 → paramrf-0.35.2}/tests/test_utils/test_compress.py +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Run Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repo
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Install Compilers and MPI
|
|
18
|
+
run: |
|
|
19
|
+
sudo apt-get update
|
|
20
|
+
sudo apt-get install -y gfortran libopenmpi-dev openmpi-bin
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.11'
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies and smoke test package import
|
|
28
|
+
run: scripts/install-test-deps.sh
|
|
29
|
+
|
|
30
|
+
- name: Run Pytest
|
|
31
|
+
run: |
|
|
32
|
+
python -m pytest -rs
|
|
33
|
+
env:
|
|
34
|
+
PMRF_TESTS_NO_SKIPS: "1"
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.35.0
|
|
4
|
+
|
|
5
|
+
Parameter names, values and serialisation (#138), and the parameter API of
|
|
6
|
+
ADR-0002 (#146). Downstream users pinning an exact version: every breaking
|
|
7
|
+
change below ships in **0.35.0**.
|
|
8
|
+
|
|
9
|
+
Name-keyed operations are now free functions rather than methods, values are
|
|
10
|
+
read and written in the units they were declared in, and changing a value no
|
|
11
|
+
longer recompiles a model's RF methods.
|
|
12
|
+
|
|
13
|
+
### Breaking changes (0.35.0)
|
|
14
|
+
|
|
15
|
+
- **Parameter API (#146):** name-keyed operations are free functions, so they
|
|
16
|
+
also work on a collection such as `(model, noise_model)`. Removed:
|
|
17
|
+
`Module.named_params`, `values`, `with_values`, `with_free`, `with_fixed`,
|
|
18
|
+
`map` and `at`; `Module.tied` and `Model.tied`; `Param.as_fixed`, `as_free`
|
|
19
|
+
and `at`; and the public `Param.wrap`. Use `prf.params`, `prf.param_values`,
|
|
20
|
+
`prf.update` and `prf.tie`. There are no aliases or deprecation shims.
|
|
21
|
+
- **Parameter API (#146):** `Module` has no public methods. `Model` keeps its RF
|
|
22
|
+
methods, which are now fixed by a checked-in allowlist.
|
|
23
|
+
- **Values (#146):** `Param.value`, `prf.param_values` and `prf.update` use the
|
|
24
|
+
**declared** value, the number as written in the units the parameter's scale
|
|
25
|
+
declares, so `prf.update(m, {'C': 3.0})` on a pF parameter sets 3 pF, not 3 F.
|
|
26
|
+
This reverses the physical-value behaviour `prf.replace(p, value=...)` had
|
|
27
|
+
earlier in this release.
|
|
28
|
+
- **Values (#146):** a scale on a value overrides the field's scale instead of
|
|
29
|
+
multiplying with it, so a `Param` with `scale=1e-9` passed into a pF field is
|
|
30
|
+
nF. `Param.scale` is `None` when the parameter declares none.
|
|
31
|
+
- **Values (#146):** `Param.unscaled_value` is removed; the three spaces are
|
|
32
|
+
`Param.value` (declared), `physical_value` and `raw_value`.
|
|
33
|
+
- **Values (#146):** the `Param` field holding the Parax variable is renamed
|
|
34
|
+
from `raw_value` to `variable`, and the bijector properties are now
|
|
35
|
+
`raw_to_declared_bijector` and `declared_to_physical_bijector`.
|
|
36
|
+
- **Values (#146):** a model's `repr` shows declared values, not scaled ones.
|
|
37
|
+
- **Inference (#146):** the minimiser and samplers run on raw-space values, over
|
|
38
|
+
a name-keyed dict rather than a flat vector. `pmrf.utils.optix`'s lens is
|
|
39
|
+
internal; nothing public returns a `Lens`.
|
|
40
|
+
- **Inference (#146):** `prf.log_prior` is a density in the space asked for, so
|
|
41
|
+
a raw-space prior carries the constraint's Jacobian and scale terms. Saved
|
|
42
|
+
results that stored physical values need re-reading in declared space.
|
|
43
|
+
- **Inference (#151):** `run_minimizer`'s `use_bounds` argument is removed. A
|
|
44
|
+
bounded solver is given infinite raw bounds, because raw space is the whole
|
|
45
|
+
real line and each parameter's bijector keeps its constraints.
|
|
46
|
+
- **Inference (#151):** a parameter starting exactly on one of its bounds
|
|
47
|
+
raises for the minimiser and for joint and split samplers: its raw value is
|
|
48
|
+
infinite and cannot move. Hypercube samplers work in declared space and
|
|
49
|
+
accept it.
|
|
50
|
+
- **Values (#146):** `prf.derivative` differentiates each parameter with
|
|
51
|
+
respect to its declared value, so the derivative for a pF parameter is per pF;
|
|
52
|
+
`space='physical'` gives the old per-SI-unit result. Each result keeps its
|
|
53
|
+
argument's structure, wrappers included, instead of the unwrapped one. A fixed
|
|
54
|
+
parameter gets its sensitivity rather than zero, and a tie's source includes
|
|
55
|
+
the path through the tie.
|
|
56
|
+
- **Names (#133):** parameter names no longer include tied targets; a tie's
|
|
57
|
+
target is derived, not stored.
|
|
58
|
+
- **Names (#133):** wrapper path parts (`Tied`, `Probabilistic`, `Wrapped`) are
|
|
59
|
+
dropped from parameter names.
|
|
60
|
+
- **Names (#133):** a name collision raises.
|
|
61
|
+
- **Names (#133):** `prf.unfreeze` also unfreezes frozen parameters inside the
|
|
62
|
+
value.
|
|
63
|
+
- **Names (#133):** string dict keys that are valid identifiers give dotted
|
|
64
|
+
names (`components.cable.length`) instead of the bracket form.
|
|
65
|
+
- **Names (#146):** a named model held in a dict drops its key, and top-level
|
|
66
|
+
dict keys do not add a namespace layer.
|
|
67
|
+
- **Values (#134):** the `Param` constructor rejects a raw value together with
|
|
68
|
+
`distribution` or `constraint`.
|
|
69
|
+
- **Save format (#136):** prf files carry a header
|
|
70
|
+
(`{"format": "prf", "schema_version": 1, "paramrf_version": ..., "tree": ...}`).
|
|
71
|
+
`prf.load` rejects files without it, or with a `schema_version`
|
|
72
|
+
other than 1, so files saved by earlier versions
|
|
73
|
+
cannot be loaded.
|
|
74
|
+
- **Save format (#136):** `prf.save` writes every field, defaults included.
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- `prf.params` and `prf.param_values` read a model's parameters by name, and
|
|
79
|
+
`prf.log_prior` scores them, each over a selector and one of the three value
|
|
80
|
+
spaces (#146).
|
|
81
|
+
- `prf.update`, one verb for changing a model: values by name, a value or fixed
|
|
82
|
+
state over a selector, a new sub-model, or a function of the old part (#146).
|
|
83
|
+
- `prf.tie` as a free function (#146).
|
|
84
|
+
- One name resolver behind every name-based operation; names resolve through
|
|
85
|
+
frozen parameters and after evaluating a `Touchstone`-backed model (#133).
|
|
86
|
+
- `prf.replace` works on `Param`, keeping prior, constraint, fixed state, scale,
|
|
87
|
+
name and metadata (#134).
|
|
88
|
+
- `pmrf.serialization.SCHEMA_VERSION` and `FORMAT` constants, and a clearer
|
|
89
|
+
`ImportError` when a saved class cannot be imported (#136).
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
- Changing a parameter's value no longer recompiles a model's RF methods. The
|
|
94
|
+
value forms of `prf.update` keep the tree structure and every leaf's dtype,
|
|
95
|
+
shape and weak type (#130, #146).
|
|
96
|
+
- Compiling `model.s(freq)` for a Touchstone-backed model no longer takes
|
|
97
|
+
minutes: interpolation is vectorised over port pairs rather than looped. At
|
|
98
|
+
50 ports with linear interpolation, the first call drops from 70 s to 0.4 s;
|
|
99
|
+
100 ports no longer times out. S-parameter data stays static, which keeps
|
|
100
|
+
per-call evaluation fast (#130, #152).
|
|
101
|
+
- `pmrf.__version__` is now set; it was looked up under the wrong
|
|
102
|
+
distribution name (#136).
|
|
103
|
+
- The `Model.build` deprecation warning is emitted once per class, and now
|
|
104
|
+
points to plain functions for composites with no parameters of their own
|
|
105
|
+
(#137).
|
|
106
|
+
- `pmrf.__all__` no longer lists `Topology` and `Initvar`, which do not exist
|
|
107
|
+
(#146).
|
|
108
|
+
|
|
109
|
+
### Documentation
|
|
110
|
+
|
|
111
|
+
- New "Working with parameter names" page in core concepts: how names are
|
|
112
|
+
formed, the three value spaces, selectors, the forms of `prf.update`, ties,
|
|
113
|
+
and what recompiles. The "Parameter naming and model manipulation" example
|
|
114
|
+
walks through the same operations on the new API (#146).
|
|
115
|
+
- `Module` and `Substrate` explain that passing the same instance to two
|
|
116
|
+
sibling fields gives independent parameters, and how to share one (#137).
|
|
117
|
+
|
|
118
|
+
## Unreleased
|
|
119
|
+
|
|
120
|
+
- Complete Tesche coaxial conductor physics across the low-frequency regime,
|
|
121
|
+
and pass evaluated material properties to pure coaxial formulations.
|
|
122
|
+
- Correct microstrip results by enabling Kirschning--Jansen modal dispersion by
|
|
123
|
+
default. Set `dispersion=None` on `MicrostripLine` to retain the quasi-static
|
|
124
|
+
pipeline explicitly.
|
|
125
|
+
- Add the Hammerstad--Jensen microstrip formulation and selectable complex
|
|
126
|
+
(ADS-like) and real (QUCS-like) permittivity conventions.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "ParamRF: A Modern Framework for Parametric Radio Frequency Modeling"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: "Allen"
|
|
7
|
+
given-names: "Gary"
|
|
8
|
+
orcid: "https://orcid.org/0009-0005-6572-598X"
|
|
9
|
+
- family-names: "De Villiers"
|
|
10
|
+
given-names: "Dirk"
|
|
11
|
+
orcid: "https://orcid.org/0000-0003-1273-5365"
|
|
12
|
+
repository-code: "https://github.com/gvcallen/paramrf"
|
|
13
|
+
license: "Apache-2.0"
|
|
14
|
+
version: "0.34.4"
|
|
@@ -1,8 +1,62 @@
|
|
|
1
1
|
# ParamRF domain context
|
|
2
2
|
|
|
3
|
-
Vocabulary for
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Vocabulary for ParamRF's domain layers. Terms here are the ones the code uses;
|
|
4
|
+
prefer them over synonyms. Each entry points at the class that owns the maths
|
|
5
|
+
rather than repeating it.
|
|
6
|
+
|
|
7
|
+
## Parameters
|
|
8
|
+
|
|
9
|
+
Vocabulary from ADR-0002.
|
|
10
|
+
|
|
11
|
+
### Param
|
|
12
|
+
|
|
13
|
+
A named, possibly bounded or probabilistic value in a model: `pmrf.Param`,
|
|
14
|
+
wrapping a Parax **variable** (the field `variable`). A **parameter name** is
|
|
15
|
+
the dotted path #133's resolver gives it (`feed_coax.dielectric.ep_r`), the key
|
|
16
|
+
for saved results, ties and selectors.
|
|
17
|
+
|
|
18
|
+
### Space
|
|
19
|
+
|
|
20
|
+
Where a parameter's number lives. Every surface defaults to **declared**.
|
|
21
|
+
|
|
22
|
+
- **raw**: the latent, unbounded array optimisers and samplers move through.
|
|
23
|
+
- **declared**: the number as written, in the units the parameter's scale
|
|
24
|
+
declares (2.0 for 2 pF). Construction, bounds, priors and `Param.value` are
|
|
25
|
+
in declared space.
|
|
26
|
+
- **physical**: the scaled, SI value (2e-12).
|
|
27
|
+
|
|
28
|
+
*Avoid:* "unconstrained space" (reads as a parameter without bounds; that is
|
|
29
|
+
`prf.Unconstrained`), "unscaled" and "constrained" for declared space, "unit
|
|
30
|
+
space" (the unit hypercube).
|
|
31
|
+
|
|
32
|
+
### Scale
|
|
33
|
+
|
|
34
|
+
The units a value is written in: physical = declared × scale. An explicit scale
|
|
35
|
+
on a value overrides a field's default; scales never multiply.
|
|
36
|
+
|
|
37
|
+
### Fixed and frozen
|
|
38
|
+
|
|
39
|
+
- **Fixed**: a parameter state. The parameter keeps its name and prior and is
|
|
40
|
+
excluded from optimisation. Toggled with `prf.update(..., fixed=)`.
|
|
41
|
+
- **Frozen**: an opaque subtree (`prf.freeze`), for constant data. Name-based
|
|
42
|
+
operations never act on it.
|
|
43
|
+
|
|
44
|
+
### Update
|
|
45
|
+
|
|
46
|
+
`prf.update` returns a copy of a model with the parts a **selector** picks
|
|
47
|
+
replaced. A selector is a parameter name, a glob over names, a sequence of
|
|
48
|
+
names, or a callable. A **validated update** (a name → value mapping,
|
|
49
|
+
`value=`, `fixed=`) goes through each parameter's constructor; a **structural
|
|
50
|
+
update** (a new node, `fn=`) bypasses validation. `prf.replace` is the plain
|
|
51
|
+
dataclass field replace, not an update.
|
|
52
|
+
|
|
53
|
+
*Avoid:* "set values", "with values"; "update" for an optimiser step.
|
|
54
|
+
|
|
55
|
+
### Parameter values
|
|
56
|
+
|
|
57
|
+
`prf.param_values`: a name-keyed dict of arrays in one space, the form values
|
|
58
|
+
take when crossing ParamRF's boundary. Not flattened; a 1-D vector exists only
|
|
59
|
+
inside adapters that need one.
|
|
6
60
|
|
|
7
61
|
## Line modelling
|
|
8
62
|
|
|
@@ -73,6 +127,7 @@ paper with no ParamRF objects in sight.
|
|
|
73
127
|
|
|
74
128
|
## Decisions
|
|
75
129
|
|
|
76
|
-
`docs/adr/` records the decisions behind
|
|
130
|
+
`docs/adr/` records the decisions behind these layers. Read
|
|
77
131
|
`docs/adr/0001-line-modelling-architecture.md` before changing a strategy
|
|
78
|
-
interface or a default.
|
|
132
|
+
interface or a default, and `docs/adr/0002-parameter-api.md` before adding a
|
|
133
|
+
method, a public function or a value space.
|
|
@@ -8,25 +8,18 @@ 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
|
|
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`):
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
4. **External Inference Dependencies (Optional):** If you plan on working on the Bayesian inference module (`pmrf.infer`), you may need to install our custom `distreqx` fork and PolyChord. Note that PolyChord requires C++ and Fortran compilers (like `mpicxx` and `mpifort`) to be installed on your system:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
pip install git+https://github.com/gvcallen/distreqx.git
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
pip install git+https://github.com/PolyChord/PolyChordLite.git
|
|
23
|
-
```
|
|
13
|
+
scripts/install-test-deps.sh
|
|
14
|
+
pip install -e .[docs]
|
|
24
15
|
|
|
25
16
|
## Building docs/running tests
|
|
26
17
|
|
|
27
18
|
We use `pytest` for all unit testing. Simply run:
|
|
28
19
|
|
|
29
|
-
pytest
|
|
20
|
+
pytest -rs
|
|
21
|
+
|
|
22
|
+
Tests for optional backends skip when a backend is missing. CI sets `PMRF_TESTS_NO_SKIPS=1`, which turns any skip into a failure, so run with it locally too before opening a PR.
|
|
30
23
|
|
|
31
24
|
When writing new tests, especially for fitting and inference routines, try to use synthetic, in-memory S-parameter data (identity fits) rather than committing `.s2p` files to the repository. This keeps the test suite fast and the repository size small.
|
|
32
25
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: paramrf
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.35.2
|
|
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
|
|
10
|
+
Requires-Dist: parax>=0.10.8
|
|
11
11
|
Requires-Dist: threadpoolctl
|
|
12
12
|
Requires-Dist: eqxpress
|
|
13
13
|
Requires-Dist: jax
|
|
@@ -113,7 +113,7 @@ The code below demonstrate how to define and optimize an RLC model to satisfy a
|
|
|
113
113
|
model.plot_s_db(plot_freq, m=0, n=0, label='initial')
|
|
114
114
|
result.model.plot_s_db(plot_freq, m=0, n=0, label='optimized')
|
|
115
115
|
|
|
116
|
-
print(result.model
|
|
116
|
+
print(prf.param_values(result.model))
|
|
117
117
|
|
|
118
118
|
Next steps
|
|
119
119
|
----------
|
|
@@ -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(result.model
|
|
72
|
+
print(prf.param_values(result.model))
|
|
73
73
|
|
|
74
74
|
Next steps
|
|
75
75
|
----------
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# ADR-0002: Parameter API: free functions, one update verb, three value spaces
|
|
2
|
+
|
|
3
|
+
Status: accepted (2026-09)
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
0.35.0 (#138) made parameter names the key for saved results, ties, free sets
|
|
8
|
+
and external tooling, and added name-keyed operations as `Module` methods:
|
|
9
|
+
`values`, `with_values`, `with_free` and `with_fixed`, next to the existing
|
|
10
|
+
`named_params`, `at`, `map` and `tied`. An older ParamRF had `with_*` methods
|
|
11
|
+
and deprecated them because they inflated the API and cut against a move to a
|
|
12
|
+
functional style. There was no rule for which operations get a method, so the
|
|
13
|
+
surface grew case by case.
|
|
14
|
+
|
|
15
|
+
Four problems forced a decision:
|
|
16
|
+
|
|
17
|
+
- **Joint trees.** Fitting and inference increasingly work on collections such
|
|
18
|
+
as `(model, noise_model)`. A method on `Module` cannot reach them, so every
|
|
19
|
+
method-only operation needs a function as well, and the API grows two
|
|
20
|
+
spellings.
|
|
21
|
+
- **Scale.** Construction takes the declared value (`prf.param(scale=1e-12)`
|
|
22
|
+
then `RC(1.0, 2.0)` stores 2 pF), but `Param.value`, `values()`,
|
|
23
|
+
`with_values()` and `prf.replace(p, value=...)` use the physical, scaled
|
|
24
|
+
value. `with_values({'C': 3.0})` on that model silently sets 3 F. A `Param`
|
|
25
|
+
with its own scale passed into a scaled field multiplies the two scales
|
|
26
|
+
(`1e-9 × 1e-12`).
|
|
27
|
+
- **Recompilation (#130).** RF methods are wrapped in `eqx.filter_jit`, so any
|
|
28
|
+
change to a model's static structure recompiles. Rebuilding a parameter with
|
|
29
|
+
`model.at(name).set(prf.Unconstrained(v))`, as the docs showed, changes its
|
|
30
|
+
scale and constraint and recompiles; for a large circuit that is a minute per
|
|
31
|
+
change. `_replace_raw_value` also flips `weak_type` on the value leaf, so
|
|
32
|
+
`with_values` and `prf.replace` recompile once even though the treedef is
|
|
33
|
+
unchanged.
|
|
34
|
+
- **Flattening (#135, #142).** A proposed `prf.flatten` returned a
|
|
35
|
+
`FlatParams` object over a 1-D vector. Flattening that prominent is unusual
|
|
36
|
+
in the JAX ecosystem.
|
|
37
|
+
|
|
38
|
+
Precedent from other JAX libraries: Equinox's `Module` has no public methods;
|
|
39
|
+
Flax NNX deprecated `Module.iter_modules` and `iter_children` in favour of free
|
|
40
|
+
functions; Penzai keeps a single `.select()` gateway; NumPyro's
|
|
41
|
+
`initialize_model` exposes a potential function over a **name-keyed dict** of
|
|
42
|
+
unconstrained values and ravels only inside samplers. scikit-rf, which most
|
|
43
|
+
ParamRF users know, puts RF operations on `Network` as methods.
|
|
44
|
+
|
|
45
|
+
## Decisions
|
|
46
|
+
|
|
47
|
+
### 1. A method belongs to the class that gives it meaning
|
|
48
|
+
|
|
49
|
+
If an operation would make equal sense on a plain collection of models and
|
|
50
|
+
parameters, such as a `(model, noise_model)` tuple, it is a free function and
|
|
51
|
+
never a method. There are no exceptions.
|
|
52
|
+
|
|
53
|
+
- **`Model`** keeps RF methods: `s`, `a`, `z`, `y`, `mna`, `nports`,
|
|
54
|
+
`port_tuples`, `primary_matrix`, `build`, `expand`, `cascaded`, `flipped`,
|
|
55
|
+
`renumbered`, `terminated`, `**`, `@`, `to_skrf` and `export_touchstone`.
|
|
56
|
+
`tied` leaves; tying is parameterisation, not circuit algebra.
|
|
57
|
+
- **`Module`** has no public methods (decision 2).
|
|
58
|
+
- **`Param`** keeps read-only properties that describe it (`value`, `bounds`,
|
|
59
|
+
`distribution`, ...). `as_fixed`, `as_free` and `at` are removed; `wrap`
|
|
60
|
+
becomes private.
|
|
61
|
+
|
|
62
|
+
A test asserts that `Module` has no public methods and that `Model`'s public
|
|
63
|
+
methods equal a checked-in allowlist, so adding one is a reviewed decision. The
|
|
64
|
+
methods `__init_subclass__` generates (`s_db`, `s_mn_mag`, ...) and the plotting
|
|
65
|
+
names `__getattr__` serves are RF and allowed; the test skips them by pattern
|
|
66
|
+
and says so. Replacing them is out of scope.
|
|
67
|
+
|
|
68
|
+
This matches what scikit-rf users expect, where RF operations are methods, and
|
|
69
|
+
what JAX users expect, where tree operations are functions.
|
|
70
|
+
|
|
71
|
+
### 2. `Module` is a contract, not a toolbox
|
|
72
|
+
|
|
73
|
+
Without methods, `Module` still does work nothing else does. Its `name` is what
|
|
74
|
+
makes a named module collapse the path to its left into a namespace, which name
|
|
75
|
+
resolution depends on. `pmrf.modules.validate` rejects raw float JAX arrays in
|
|
76
|
+
its fields, which are ambiguous between free and fixed parameters. It carries
|
|
77
|
+
`metadata`, gives the unwrapped `repr`, and is the base of `Model`, losses,
|
|
78
|
+
likelihoods, kernels, materials and evaluators. Subclassing it says the object
|
|
79
|
+
takes part in naming and validation. Its docstring says so.
|
|
80
|
+
|
|
81
|
+
### 3. One verb for changing a model: `prf.update`
|
|
82
|
+
|
|
83
|
+
`prf.update` returns a copy of a model in which the parts a selector picks are
|
|
84
|
+
replaced. Exactly one form says what with:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
prf.update(model, {'L1.L': 3.0, 'C1.C': 2.0}) # parameter values by name
|
|
88
|
+
prf.update(model, 'L1.L', value=3.0) # parameter fields on a selection
|
|
89
|
+
prf.update(model, 'cable.*', fixed=True) # fixed state
|
|
90
|
+
prf.update(model, 'cascade[1]', Short()) # a new sub-model or node
|
|
91
|
+
prf.update(model, 'load.*', fn=lambda p: ...) # a function of the old part
|
|
92
|
+
prf.update(model, v, space='raw') # write-back from an optimiser or sampler
|
|
93
|
+
prf.update(param, value=3.0) # selector omitted: the root itself
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
It replaces `with_values`, `with_free`, `with_fixed`, `Module.map`,
|
|
97
|
+
`Module.at`, `Param.as_fixed`, `Param.as_free` and `Param.wrap`.
|
|
98
|
+
|
|
99
|
+
- **Selectors** are parameter names, `fnmatch` globs over them, sequences of
|
|
100
|
+
names, or callables, resolved by the #133 resolver.
|
|
101
|
+
- **Two tiers, set by the form.** The mapping, `value=` and `fixed=` forms go
|
|
102
|
+
through each parameter's constructor: they validate bounds and keep the prior,
|
|
103
|
+
constraint, scale, name and metadata. The node and `fn=` forms are
|
|
104
|
+
structural: they bypass converters and validation, and the docstring says so.
|
|
105
|
+
- **The mapping form** is recognised only as the second positional argument
|
|
106
|
+
with every key a string. Its values may be arrays or `Param` objects. Any
|
|
107
|
+
other second argument is a selector, and a form mismatch raises an error that
|
|
108
|
+
lists the forms.
|
|
109
|
+
- **`fixed=`** is additive. `fixed=False` frees a parameter even if it was
|
|
110
|
+
created fixed, and parameters the selector does not match are untouched.
|
|
111
|
+
"Only these free" is `update(update(m, '*', fixed=True), names, fixed=False)`.
|
|
112
|
+
- **Value forms keep the jit cache key.** The mapping, `value=` and `space=`
|
|
113
|
+
forms never change the treedef, or any leaf's dtype, shape or `weak_type`
|
|
114
|
+
(decision 10). Changing `fixed=`, or any structural form, changes the model's
|
|
115
|
+
structure, and recompiling is expected.
|
|
116
|
+
- **Not an optimiser step.** In fitting, "updates" also means Optax gradient
|
|
117
|
+
steps; the docstring says `update` is neither.
|
|
118
|
+
|
|
119
|
+
`prf.replace` stays as the plain `dataclasses.replace`: fields of one object,
|
|
120
|
+
unvalidated, able to break a type. Its docstring points to `update` for
|
|
121
|
+
anything name-based.
|
|
122
|
+
|
|
123
|
+
`prf.tie(model, target, source, fn=identity)` stays a separate verb. A tie is
|
|
124
|
+
not a replacement: its target is recomputed from its source every time the
|
|
125
|
+
model is unwrapped.
|
|
126
|
+
|
|
127
|
+
### 4. Reading: `prf.params` and `prf.param_values`
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
prf.params(model, where='*', *, free_only=False) # dict[str, Param]
|
|
131
|
+
prf.param_values(model, where='*', *, free_only=False, space='declared') # dict[str, Array]
|
|
132
|
+
prf.log_prior(model, *, space='declared') # scalar
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
A user thinks "the parameters of my model", so `params` returns `Param`
|
|
136
|
+
objects, whose `repr` shows value, bounds and prior. `param_values` is what
|
|
137
|
+
`update` accepts and what optimisers use; a bare `values` was rejected as too
|
|
138
|
+
vague at top level, where it could mean S-parameter data. `named_params`'
|
|
139
|
+
`full_params` and `namespace_separator` are dropped.
|
|
140
|
+
|
|
141
|
+
The documented identity, which is also the regression test of decision 10:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
prf.update(m, prf.param_values(m, space=s), space=s) # same structure, same cache key
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
All functions are defined in `pmrf.parameters` and re-exported at top level.
|
|
148
|
+
|
|
149
|
+
### 5. Three value spaces: `raw`, `declared`, `physical`
|
|
150
|
+
|
|
151
|
+
| Space | Meaning | Example (2 pF, `scale=1e-12`) |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| `raw` | the latent, unbounded array an optimiser or sampler moves through | constraint bijector inverse of 2.0 |
|
|
154
|
+
| `declared` | the number as written, in the units the parameter's scale declares | `2.0` |
|
|
155
|
+
| `physical` | the scaled, SI value | `2e-12` |
|
|
156
|
+
|
|
157
|
+
`declared` is the default everywhere, and every user-facing surface agrees with
|
|
158
|
+
construction: `Param(value=...)`, bounds, priors, `repr`, `Param.value`,
|
|
159
|
+
`param_values` and `update`. Distributions and bounds are authored in declared
|
|
160
|
+
space.
|
|
161
|
+
|
|
162
|
+
`Param` gets one property per space: `value` (declared), `physical_value` and
|
|
163
|
+
`raw_value` (the latent array). `unscaled_value` is removed. The field
|
|
164
|
+
currently named `raw_value`, which holds the Parax variable, is renamed
|
|
165
|
+
`variable`. The bijector properties become `raw_to_declared_bijector` and
|
|
166
|
+
`declared_to_physical_bijector`; "constrained" and "unscaled" are no longer
|
|
167
|
+
used as space names.
|
|
168
|
+
|
|
169
|
+
`log_prior` supports all three spaces: declared is the density as written,
|
|
170
|
+
physical adds −log|scale| per parameter, and raw adds the constraint bijector's
|
|
171
|
+
log|det J| as well. Each docstring states its measure.
|
|
172
|
+
|
|
173
|
+
**Why `raw`, not `unconstrained`.** ParamRF's users are mostly RF engineers,
|
|
174
|
+
who read "unconstrained" as "a parameter without bounds", which is what
|
|
175
|
+
`prf.Unconstrained` creates. The code already used "raw" for this reason.
|
|
176
|
+
**Why not `unit`.** In fitting, "unit space" is the unit hypercube nested
|
|
177
|
+
samplers work in, which ParamRF's hypercube sampler maps to.
|
|
178
|
+
**Why not `unscaled`, `normalized`, `per_unit` or `engineering`.** `declared`
|
|
179
|
+
says what the value is rather than what has not happened to it; `normalized`
|
|
180
|
+
means z = Z/Z₀ in RF and [0, 1] in optimisation; `per_unit` is power-systems
|
|
181
|
+
jargon; "engineering units" means the scaled value in instrumentation.
|
|
182
|
+
|
|
183
|
+
### 6. Scale is the units a value is written in
|
|
184
|
+
|
|
185
|
+
A field's scale is a default unit. An explicit scale on the value overrides it;
|
|
186
|
+
the two are never multiplied. The factories and `as_param` take `scale=None`,
|
|
187
|
+
meaning "inherit the field's", so `prf.Unconstrained(2.0)` passed into a pF
|
|
188
|
+
field is 2 pF, and `prf.Unconstrained(2.0, scale=1e-9)` is 2 nF.
|
|
189
|
+
|
|
190
|
+
This reverses 0.35.0's `prf.replace(p, value=...)`, which took the physical
|
|
191
|
+
value; `update(p, value=...)` takes the declared one.
|
|
192
|
+
|
|
193
|
+
### 7. Fixed and frozen are different things
|
|
194
|
+
|
|
195
|
+
- **Fixed** is a parameter state. The parameter is still a `Param`, still named
|
|
196
|
+
and still carries its prior; it is excluded from optimisation.
|
|
197
|
+
`update(..., fixed=)` toggles it.
|
|
198
|
+
- **Frozen** (`prf.freeze`, `prf.unfreeze`) makes a subtree opaque. It is for
|
|
199
|
+
constant data, such as `field(converter=prf.freeze)`, and for hiding whole
|
|
200
|
+
subtrees.
|
|
201
|
+
|
|
202
|
+
The name-based operations act on fixed, never on frozen.
|
|
203
|
+
|
|
204
|
+
### 8. No public flattening
|
|
205
|
+
|
|
206
|
+
Parameter values cross ParamRF's boundary as name-keyed dicts, which are
|
|
207
|
+
pytrees that Optax, Optimistix, BlackJAX and `jax.grad` take directly.
|
|
208
|
+
Raveling to a 1-D vector stays inside the adapters that need it, such as the
|
|
209
|
+
SciPy solver (`pmrf/optimize/solvers/scipy.py`) and non-JAX samplers.
|
|
210
|
+
`prf.flatten` and `FlatParams` (#142) are not added. A public ravel helper, with
|
|
211
|
+
one name per array element, can be added when a non-JAX consumer needs it; it
|
|
212
|
+
would sit on top of `param_values`, not replace it.
|
|
213
|
+
|
|
214
|
+
The substance of #142 is kept: the raw-space log prior with the Jacobian and
|
|
215
|
+
scale terms, name alignment, and a single implementation behind the minimiser
|
|
216
|
+
and samplers.
|
|
217
|
+
|
|
218
|
+
### 9. Public names describe the domain, not the data structure
|
|
219
|
+
|
|
220
|
+
Public functions have no `tree_` prefix; most users do not know what a pytree
|
|
221
|
+
is and should not need to. `tree_*` names are for private helpers. Docs say "a
|
|
222
|
+
model, or any collection of models and parameters", and reserve "pytree" for
|
|
223
|
+
an advanced page.
|
|
224
|
+
|
|
225
|
+
### 10. Recompilation is prevented by keeping structure, not by changing the cache
|
|
226
|
+
|
|
227
|
+
The automatic `eqx.filter_jit` on RF methods and its cache key stay as they
|
|
228
|
+
are. Dropping the automatic jit would make `model.s(freq)` slow for the users
|
|
229
|
+
decision 1 keeps methods for; removing `name` and `metadata` from the treedef
|
|
230
|
+
would complicate name resolution for a rare case.
|
|
231
|
+
|
|
232
|
+
Instead, the structure-preserving forms of `update` guarantee an unchanged
|
|
233
|
+
cache key, and a test enforces it for every such form: treedef, dtype, shape and
|
|
234
|
+
`weak_type` of every leaf. The docs say plainly that changing a parameter's
|
|
235
|
+
value never recompiles and rebuilding it does.
|
|
236
|
+
|
|
237
|
+
## Consequences
|
|
238
|
+
|
|
239
|
+
- **Breaking, in one minor release.** Removed: `Module.named_params`, `values`,
|
|
240
|
+
`with_values`, `with_free`, `with_fixed`, `map`, `at`, `tied`; `Model.tied`;
|
|
241
|
+
`Param.as_fixed`, `as_free`, `at`, `unscaled_value`; public `Param.wrap`.
|
|
242
|
+
Renamed: the `Param.raw_value` field to `variable`, and the bijector
|
|
243
|
+
properties. Changed: `Param.value` returns the declared value; scales
|
|
244
|
+
override instead of multiplying. No aliases or deprecation shims.
|
|
245
|
+
- `pmrf.utils.optix`'s lens becomes internal or is deleted; nothing public
|
|
246
|
+
returns a `Lens`.
|
|
247
|
+
- Joint-tree names keep #133's rules. A named model inside a dict drops its key,
|
|
248
|
+
and a collision raises; top-level dict keys do not become a namespace layer.
|
|
249
|
+
- Saved results keyed by name keep working; results that stored physical
|
|
250
|
+
values need re-reading in declared space.
|
|
251
|
+
- Deferred to their own issues: reducing the top-level and submodule surface
|
|
252
|
+
(including `__all__` listing `Topology` and `Initvar`, which do not exist);
|
|
253
|
+
compile duration for large S-parameter blocks (#130, the per-port
|
|
254
|
+
interpolation loop); the generated `s_db`-style methods; flat vectors for
|
|
255
|
+
non-JAX tools.
|
|
@@ -20,6 +20,19 @@ Core Primitives
|
|
|
20
20
|
pmrf.Random
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
Working with Parameters
|
|
24
|
+
-----------------------
|
|
25
|
+
|
|
26
|
+
.. autosummary::
|
|
27
|
+
:toctree: generated/
|
|
28
|
+
|
|
29
|
+
pmrf.params
|
|
30
|
+
pmrf.param_values
|
|
31
|
+
pmrf.log_prior
|
|
32
|
+
pmrf.update
|
|
33
|
+
pmrf.tie
|
|
34
|
+
|
|
35
|
+
|
|
23
36
|
Main Modules
|
|
24
37
|
------------
|
|
25
38
|
|
|
@@ -9,7 +9,7 @@ The Model
|
|
|
9
9
|
|
|
10
10
|
Under the hood, ParamRF uses the `Equinox <https://docs.kidger.site/equinox/api/module/module/>`_ library to interoperate with JAX. This means that :class:`pmrf.Model` is an `Equinox Module <https://docs.kidger.site/equinox/api/module/module/>`_, a `JAX PyTree <https://docs.jax.dev/en/latest/pytrees.html>`_ and a Python `dataclass <https://docs.python.org/3/library/dataclasses.html>`_. If these concepts are completely foreign to you, do not worry. The practical consequences of this are:
|
|
11
11
|
|
|
12
|
-
* **Models are immutable**. Models cannot be mutated (``model.x = 5.0`` will throw an error). Rather, they represent "pure functions" which store their parameters alongside. This means that models should *never* contain any fields that can be derived from other fields (state should be "pure"), and should also not reference other objects in the model (using the same parameter object twice will result in two separate parameters!). Instead, :
|
|
12
|
+
* **Models are immutable**. Models cannot be mutated (``model.x = 5.0`` will throw an error). Rather, they represent "pure functions" which store their parameters alongside. This means that models should *never* contain any fields that can be derived from other fields (state should be "pure"), and should also not reference other objects in the model (using the same parameter object twice will result in two separate parameters!). Instead, :func:`pmrf.update` returns a copy of a model with the parts you select replaced; see :doc:`parameter_names`. Although this approach may feel new to some, the end result is improved optimization performance and differentiation capabilities.
|
|
13
13
|
* **Models are lazy**. Since models only store their parameters (and not their S-matrix or frequency), they do not perform any computation at initialization. Rather, their response is only evaluated when one of their methods (e.g. :meth:`pmrf.Model.s`) is passed a :class:`~pmrf.Frequency` object *as input*. This is in contrast to other, purely object-oriented libraries (such as :mod:`scikit-rf`).
|
|
14
14
|
* **Models are JAX-native**. Models are simply JAX `PyTrees <https://docs.jax.dev/en/latest/pytrees.html>`_, meaning they can be passed around in any JAX context. This means that they can be compiled *just-in-time* (JIT) for enhanced performance and simulation on other platforms (GPUs, TPUs etc) and also used for many advanced JAX features (such as for vectorization via :func:`jax.vmap` and differentiation via :func:`jax.jacfwd`). See the :doc:`jax_overview` section for more details.
|
|
15
15
|
|
|
@@ -11,7 +11,7 @@ Standard Python is interpreted, which can introduce significant overhead. JAX by
|
|
|
11
11
|
|
|
12
12
|
When a JIT-compiled function is called, it is not immediately executed. Instead, JAX "traces" the function's execution using abstract values. This trace builds a static computation graph in an intermediate representation called **XLA** (Accelerated Linear Algebra). The XLA compiler then optimizes this graph by merging operations, reducing memory allocation, and compiling it to a specific hardware architecture (CPU, GPU, or TPU).
|
|
13
13
|
|
|
14
|
-
In ParamRF, all models and evaluators are designed to be JIT-compatible. Because JAX relies on this static tracing mechanism, functions passed to the JIT compiler must be *pure* (stateless and lacking side-effects). This functional paradigm is the underlying reason why ParamRF models are immutable; rather than modifying a model's attributes in-place,
|
|
14
|
+
In ParamRF, all models and evaluators are designed to be JIT-compatible. Because JAX relies on this static tracing mechanism, functions passed to the JIT compiler must be *pure* (stateless and lacking side-effects). This functional paradigm is the underlying reason why ParamRF models are immutable; rather than modifying a model's attributes in-place, :func:`pmrf.update` returns a modified copy.
|
|
15
15
|
|
|
16
16
|
Differentiability and Autodifferentiation
|
|
17
17
|
-----------------------------------------
|
|
@@ -64,7 +64,7 @@ This allows you to easily create and evaluate entire batches of models simultane
|
|
|
64
64
|
|
|
65
65
|
Parax and Unwrapping
|
|
66
66
|
--------------------
|
|
67
|
-
ParamRF builds on top of the JAX library `Parax <https://github.com/gvcallen/parax>`_ for parameters and constraints. Parax allows parameters (and entire models) to be
|
|
67
|
+
ParamRF builds on top of the JAX library `Parax <https://github.com/gvcallen/parax>`_ for parameters and constraints. Parax allows parameters (and entire models) to be fixed, scaled, constrained, or tied together. To accomplish this, Parax makes use of a concept known as *unwrapping*. To initialize a *wrapper*, the relevant parameter or object is *wrapped* in the desired class (for example, a "scale" wrapper). Then, to apply the wrapper, the object is *unwrapped*. This mechanism is what allows parameters to be tied together using :func:`pmrf.tie`, or for parameters to remain bounded, *even* when using an unbounded optimization algorithm.
|
|
68
68
|
|
|
69
69
|
In ParamRF, unwrapping can be done manually using :func:`pmrf.unwrap` (which is an alias to :func:`parax.unwrap`). It is also automatically applied in ParamRF for RF response methods such as :meth:`pmrf.Model.s` via the :func:`pmrf.unwrap_self` annotation, as well as internally during optimization and inference. However, if you are using non-standard methods on your models and simply want to evaluate them (for example in a Jupyter notebook), then you should manually unwrap using :func:`pmrf.unwrap`, or annotate your method using :func:`pmrf.unwrap_self` where relevant.
|
|
70
70
|
|