Releases: ComPWA/tensorwaves
TensorWaves 0.4.3
TensorWaves 0.4.2
See all documentation for this version here.
💡 New features
- Added minuit_modifier constructor argument (#399)
🐛 Bug fixes
- Speed-up prepare_caching() with sympy.Basic.xreplace (#403)
🔨 Internal maintenance
Added support for AmpForm v0.12.3 (#406)
AmpForm v0.12.3 introduces a small change through ComPWA/ampform#211: BoostZ
etc becomes BoostZMatrix
. This needs to be fixed in the TensorFlow printer.
Added support for AmpForm v0.12.4 (#417)
Added TensorFlow printer instructions for _BoostZMatrixImplementation
etc. See release notes AmpForm v0.12.4.
Switched to new import attrs API (#414)
See import attrs
and attrs
TNG.
📝 Documentation
Usage notebooks now show how to get a Hesse from FitResult.specifics (#401)
Also fixes a small bug: callbacks that write to disk skip writing when computing the Hesse.
Preview here.
Improved docstrings of prepare_caching() and create_cached_function() (#403)
Improved the docstrings of both functions, preview here.
Code examples now automatically to APIs as if it's an IDE (#405)
- All code examples are now clickable with links to corresponding reference documentation (also external links APIs) with
sphinx-codeautolink
. Closes ComPWA/compwa.github.io#106 - Installed
jupyterlab-myst
- Updated to the first non-beta black release 22.1.0. Most important style effect: no space around power operator
**
.
Second level in left sidebar is unfolded by default (#407)
Links to graphviz
's API are now also embedded correctly. Follow-up to #405.
Explained how to pin dependencies with Conda (#411)
Rewrote the installation page a bit so that it's clearer how to pin all dependencies with Conda. Preview here.
Illustrated how to use create_cached_function() in PWA notebook (#412)
Added an example of how to use create_cached_function()
in combination with an Estimator
. Preview here.
Added instructions how to install from Git repository with optional dependencies (#413)
Added an additional install example that shows how to install a specific branch or tag with pip
from Git with optional dependencies. Preview here.
🖱️ Developer Experience
Change upgrade cron job to bi-weekly (#398 and #408)
Automated changes by create-pull-request GitHub action
Type aliases in API are now abbreviated (#404)
Compare API v0.4.1 and preview of this PR.
Installed jupyterlab-myst (#405)
See jupyterlab-myst
Tests can now be run with specific versions of dependencies (#410 and #416)
Adds a workflow_dispatch
with inputs that allows running all tests manually with the latest version of AmpForm installed.
TensorWaves 0.4.1
See all documentation for this version here.
💡 New features
Implemented create_cached_function() (#397)
Closes #358
Expression tree optimizations sketched here have been bundled in a new function create_cached_function()
. A usage notebook can be previewed here.
⚠️ Interface
TensorFlow has become an optional dependency (#394)
All computational backends are now optional dependencies (apart from NumPy). So for instance, to install TensorWaves with JAX, run:
pip install tensorwaves[jax]
To do amplitude analysis, install with:
pip install tensorwaves[jax,pwa]
🐛 Bug fixes
Progress bar of domain generator is hidden in IntensityDistributionGenerator (#396)
Closes #395
import ampform
import qrules
from ampform.dynamics.builder import create_relativistic_breit_wigner_with_ff
from tensorwaves.data import (
IntensityDistributionGenerator,
TFPhaseSpaceGenerator,
TFUniformRealNumberGenerator,
)
from tensorwaves.data.transform import SympyDataTransformer
from tensorwaves.function.sympy import create_parametrized_function
reaction = qrules.generate_transitions(
initial_state="J/psi(1S)",
final_state=["gamma", "pi0", "pi0"],
allowed_intermediate_particles=["f(0)"],
allowed_interaction_types=["strong", "EM"],
)
builder = ampform.get_builder(reaction)
resonances = reaction.get_intermediate_particles()
for p in resonances:
builder.set_dynamics(p.name, create_relativistic_breit_wigner_with_ff)
model = builder.formulate()
intensity = create_parametrized_function(
model.expression.doit(),
parameters=model.parameter_defaults,
backend="jax",
)
helicity_transformer = SympyDataTransformer.from_sympy(
model.kinematic_variables, backend="jax"
)
phsp_generator = TFPhaseSpaceGenerator(
initial_state_mass=reaction.initial_state[-1].mass,
final_state_masses={i: p.mass for i, p in reaction.final_state.items()},
)
data_generator = IntensityDistributionGenerator(
function=intensity,
domain_generator=phsp_generator,
domain_transformer=helicity_transformer,
)
rng = TFUniformRealNumberGenerator(seed=0)
phsp_momenta = phsp_generator.generate(1_000_000, rng)
data_momenta = data_generator.generate(100_000, rng)
🖱️ Developer Experience
Increased test coverage (#393)
- Wrote some additional tests for the
tensorwaves.function
module TYPE_CHECKING
is now ignored in test coverage
TensorWaves 0.4.0
See all documentation for this specific version here.
TensorWaves v0.4 has a more general interface than v0.3. Major changes are the removal of the Model
interface (#357) and generalization of the data
module (#392). This affects the way in which computational backend functions are created and the way in which hit-and-miss distributions are generated.
Some examples of syntax changes for an AmpForm HelicityModel
(model
):
v0.4.x (new)
# create function and data transformer
from tensorwaves.function.sympy import create_parametrized_function
intensity = create_parametrized_function(
expression=model.expression.doit(),
parameters=model.parameter_defaults,
backend="jax",
)
helicity_transformer = SympyDataTransformer.from_sympy(
model.kinematic_variables, backend="numpy"
)
# generate data
from tensorwaves.data import (
IntensityDistributionGenerator,
SympyDataTransformer,
TFPhaseSpaceGenerator,
TFUniformRealNumberGenerator,
)
phsp_generator = TFPhaseSpaceGenerator(
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
)
data_generator = IntensityDistributionGenerator(
domain_generator=phsp_generator,
function=intensity,
domain_transformer=helicity_transformer,
)
rng = TFUniformRealNumberGenerator(seed=0)
phsp = phsp_generator.generate(100_000, rng)
data = data_generator.generate(10_000, rng)
Note that this works for general SymPy expressions: there is no AmpForm dependency. See this page.
v0.3.x (old)
from tensorwaves.model import LambdifiedFunction, SympyModel
# create function and data transformer
sympy_model = SympyModel(
expression=model.expression.doit(),
parameters=model.parameter_defaults,
)
intensity = LambdifiedFunction(sympy_model, backend="jax")
helicity_transformer = HelicityTransformer(model.adapter)
# generate data
from tensorwaves.data import TFUniformRealNumberGenerator, generate_data, generate_phsp
from tensorwaves.data.transform import HelicityTransformer
rng = TFUniformRealNumberGenerator(seed=0)
phsp = generate_phsp(
size=100_000,
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
random_generator=rng,
)
data = generate_data(
size=10_000,
initial_state_mass=3.069,
final_state_masses={0: 0.0, 1: 0.135, 2: 0.135},
data_transformer=helicity_transformer,
intensity=intensity,
random_generator=rng,
)
💡 New features
Implemented chi-squared estimator (#387)
Also includes improvements to the documentation of estimator
module.
Implemented get_source_code function (#378)
Closes #323
- Added a convenience function
tensorwaves.function.get_source_code()
- Added read-only properties
function
andargument_order
toParametrizedBackendFunction
(parallelsattrs
-decoratedPositionalArgumentFunction
class). PositionalArgumentFunction
is now used internally inParametrizedBackendFunction
(simplifies its__call__()
method).- Symbols are not force-dummified anymore if
use_cse=False
SciPy now works with TF (#360)
Import optimizers directly from the tensorwaves.optimizer module (#360)
It's now possible to do
from tensorwaves.optimizer import Minuit2
instead of
from tensorwaves.optimizer.minuit import Minuit2
⚠️ Interface
Adapted implementation to AmpForm v0.12.x (#345)
Adapts the data
module implementation so that it can work with AmpForm v0.12.x. Closes ComPWA/ampform#182.
Some major changes:
- Keys in a
DataSample
are nowstr
only, notint
. This means that momentum samples have keys"p0"
,"p1"
, etc. instead of0
,1
. This is in accordance with theSymbol
names used in AmpForm'sHelicityModel.kinematic_variables
. - Added a function
create_function()
that creates aPositionalArgumentFunction
. This is aFunction
without parameters (compareParametrizedFunction
). The function and related class is used in theDataTransformer
implementation, which doesn't need parameters. - Data conversion can now be done with different back-ends.
Removed Model interface (#357)
This PR removes the Model
interface and related implementations. The interface was introduced with the idea to implement different types of expression trees later on (see ADR-001), but this seems to be a premature optimisation. For now, the Function
interface suffices: Function
instances can be created through specific functions.
Some major changes:
- The
Model
interface and its implementationSympyModel
have been removed tensorwaves.model
has been renamed totensorwaves.function
- There is no way to use
performance_optimize()
(for now—see #358)
This means that the workflow becomes:
# helicity_model: ampform.helicity.HelicityModel
function = create_parametrized_function(
expression=helicity_model.expression.doit(),
parameters=helicity_model.parameter_defaults,
backend="numpy",
)
instead of
model = SympyModel(
expression=helicity_model.expression.doit(),
parameters=helicity_model.parameter_defaults,
max_complexity=max_complexity,
)
function = LambdifiedFunction(model, backend="numpy")
Created ParametrizedFunction interface (#353)
The existing Function
interface has too many responsibilities: it (1) converts a DataSample
to an array or tensor and (2) distinguishes parameter variables from domain variables. This worked fine so far, because Function
was only used when optimizing, where you need to tweak those parameters. In #345 though, we need to a Function
that only does (1), for the conversion of one DataSample
(four-momenta) to another DataSample
(kinematic variables) with different back-ends.
This PR creates a new ParametrizedFunction
interface that does (1) and (2) and a 'bare' Function
interface that does only (1). The input and output types of the Function
interface are generic, so that it can be used in different types of function-like interfaces.
Related changes:
- Renamed
LambdifiedFunction
toParametrizedBackendFunction
. DataTransformer.transform()
has become a__call__
andDataTransformer
derives fromFunction
.Estimator
also derives fromFunction
: it computes an estimator value for a set of parameters.
Generalized data generation interface (#392)
Large refactoring of the data
module with the aim to generalize its hit-and-miss mechanisms to general domain DataSample
types.
Interface changes
-
Removed
generate_data()
andgenerate_phsp()
façade functions. The new way to generate phase space and hit-and-miss data samples is:from tensorwaves.data import IntensityDistributionGenerator from tensorwaves.data.phasespace import TFPhaseSpaceGenerator from tensorwaves.data.rng import TFUniformRealNumberGenerator # intensity: Function # helicity_transformer: SympyDataTransformer rng = TFUniformRealNumberGenerator(seed=0) phsp_generator = TFPhaseSpaceGenerator( initial_state_mass=3.0969, final_state_masses={0: 0.0, 1: 0.135, 2: 0.135}, ) data_generator = IntensityDistributionGenerator( domain_generator=phsp_generator, domain_transformer=helicity_transformer, function=intensity, ) phsp = phsp_generator.generate(100_000, rng) data = data_generator.generate(10_000, rng)
-
UniformRealNumberGenerator
->RealNumberGenerator
-
PhaseSpaceGenerator
->DataGenerator
-
PhaseSpaceGenerator.setup()
has been merged into the constructor (DataGenerator.__init__()
) and removed from the interface. -
Split old
TFPhaseSpaceGenerator
into an unweightedTFPhaseSpaceGenerator
(implementsDataGenerator
) and aTFWeightedPhaseSpaceGenerator
(implementsWeightedDataGenerator
).TFPhaseSpaceGenerator
can be used instead of the oldgenerate_phsp()
function. -
Collected RNGs under a new sub-module
data.rng
New features
- New interface:
DataGenerator
, which does not generate weights as opposed toFourMomentumGenerator
. IntensityDistributionGenerator
, which should be used instead ofgenerate_data()
IdentityTransformer
, which is just the identity implementation of aDataTransformer
.NumpyUniformRNG
Simplified public backend signatures (#362)
Only accepts a single str
now.
🐛 Bug fixes
Latest function call number is now also stored in Loadable callbacks (#360)
CSVSummary writes estimator value as float (#360)
TensorWaves 0.3.7
See all documentation for this version here.
💡 New features
Optimizer and Estimator type are now written to callback output (#364)
CSVSummary
was writing "estimator_type"
incorrectly (it was writing the optimizer type). This PR fixes that and adds the optimizer type as an additional entry, also to YAMLSummary
.
Lambdify with common sub-expressions (#374)
See cse
argument in sympy.lambdify()
. This fixes #345 (comment).
Note that lambdified source code becomes significantly smaller in larger expressions. Finding common sub-expressions has a small hit in performance when lambdifying, but in larger expressions, this is overcome by the fact that the output source code is smaller.
⚠️ Interface
Sympy implementation is now isolated in a sub-module (#344)
Extracted all SymPy functionality under tensorwaves.model
into a separate sub-module tensorwaves.model.sympy
.
Removed doit call from SympyModel (#347)
Closes #280
This means that doit()
has to be called on the expression first.
🐛 Bug fixes
Correct estimator value is now written to callback output (#364)
CSVSummary
was writing "estimator_type"
incorrectly (it was writing the optimizer type). This PR fixes that and adds the optimizer type as an additional entry, also to YAMLSummary
.
ComplexSqrt can now lambdified to TensorFlow as well (#365)
JAX and TensorFlow printing is forwarded to the NumPy printer, but with jax.numpy
and tensorflow.experimental.numpy
as Printer._module
respectively.
Other improvements:
- Extended tests for
find_function
and wrote a test for lambdifying AmpForm'sComplexSqrt
- Allow getting
tensorflow.Tensor
withfind_function
- Moved
_backend
module tofunction
, becausefunction
is most related to back-ends.
🔨 Internal maintenance
Swapped optimized_lambdify() implementation (#348)
Closes #322
The role of _backend_lambdify
and _sympy_lambdify
is now swapped:
_backend_lambdify
is now purely a wrapper aroundsympy.lambdify
._sympy_lambdify
offers a switch between_backend_lambdify
andoptimized_lambdify
.
These functions will change further in #292, but this is PR focuses only on the problem describe din #322.
Unit tests and integration tests are now split (#349)
All tests that require AmpForm have been seperated from proper unit tests (that require no additional dependencies). The folder structure under tests
is now:
tests
├── integration
└── unit
Additional improvements:
- Fixtures for the AmpForm tests have been parametrized:
qrules.ReactionInfo
is parametrized with the canonica-helicity and helicity formalism.SympyModel
is constructed with and withoutmax_complexity
argument in the constructor, so thatoptimized_lambdify
is tested as well.
- Improved error message of
LambdifiedFunction.update_parameters
: over-defined parameters were computed incorrectly. In addition, the error message now prints the expected parameters. - Callbacks can now take
pathlib.Path
(previously onlystr
). This makes it possible to convert theoutput_dir
fixture into aPath
as well.
Backend handling is now isolated in a sub-module (#350)
#344 created a module tensorwaves.model.backend
with the intention to collect functions that handle back-ends. This PR moves _find_function_in_backend
(which was under tensorwaves.estimator
) there as well, moves the module to the top, and hides it altogether, as these functions are implementation details.
Add unit tests for optimized_lambdify (#351)
Additional fixes:
- The faster-lambdify notebook was failing due to the interface change introduced by #348. This was not noticed, because the
%%time
statement in the cell makes the error code of that cell return 'success'. The error has been fixed and a hidden test cell has been added to prevent such failures in the future. optimized_lambdify
now directly calls_backend_lambdify
ismax_complexity
is higher than the number of nodes in the expression.
Callback output is written to separate files in the tests (#352)
Integration tests have become unstable since #349, see e.g. https://github.com/ComPWA/tensorwaves/actions/runs/1504632721, because the callback output is written to the same file when using optimized_lambdify
/ _backend_lambdify
.
Added unit tests for fast optimize (#360)
Closes #135
Adds a test under the tests/unit
folder that fits a small model with all back-ends and optimizers plus a unit test for generate_data
. This also helped fishing out some bugs (see commit history).
Other improvements:
- Import optimizers directly from the
tensorwaves.optimizer
module, e.g.:instead offrom tensorwaves.optimizer import Minuit2
from tensorwaves.optimizer.minuit import Minuit2
- CSVSummary writes estimator value as float (was complex by mistake)
- Latest function call number is also stored in
Loadable
callbacks. - Scipy now works with TF
Importing tensorwaves is now about 8x as fast (#363)
Import expensive modules inline to speed up importing tensorwaves
. This makes import tensorwaves
(and collecting tests) about 8x as fast. Profiling done with tuna as follows (see stackoverflow):
python3 -X importtime -c "import tensorwaves" 2> tw.log && tuna tw.log
Callbacks are now not run during optimize() if unspecified (#366)
Previously, if no callback was specified in the optimizer constructor, an empty CallbackList would be created and on_optimize_end etc were always called. This is (theoretically) slower.
Some other improvements:
- Use
attrs
next-generation API (see also ComPWA/compwa.github.io#90). - Avoid creating stream on creation of Loadable callback.
- Fail pytest on warnings (this helped fishing out the above bug)
Generalized SymPy printer implementation (#371)
📝 Documentation
Added API links to FitResult.specifics (#356)
Added links to the 'fit result' objects in the iminuit
and SciPy APIs.
🖱️ Developer Experience
Pytest on GitHub Actions is now stable (#355)
Fix-up to #349
Writing with a callback in a pytest fixture and then loading it back in a test led to instable CI. This PR should fix that.
Notebooks can now be run with pytest (#359)
Switch from pytest-notebook
to nbmake
. Now it's again possible to run specific notebooks from the terminal with e.g.:
pytest --nbmake docs/usage/basics.ipynb
Other small fixes:
- Avoid
fast_lambdify()
in Jupyter notebooks to speed up docs workflow. - Cast to
tuple
inParametrizedBackendFunction
.
Merge test jobs on GitHub Actions (#367)
Reorganise GitHub Action workflow for pytest. Extracted from #366 in order to identify potential performance issues. Notebooks slow after the changes introduced in #366, which may be caused by the changes to the callbacks.
Other changes;
- Treat warnings raised under pytest as errors.
- Renamed tox job for testing notebooks to
nb
.
Reduced dependencies in style requirements (#369)
Should speed up pre-commit job.
Pytest collect is now faster (#370)
Import expensive modules in the tests inline so that pytest --collect-only
is faster.
TensorWaves 0.3.4
See all documentation for this version here.
🔨 Internal maintenance
Narrowed down type hints (#332)
- Improved some of the type hints
- Enforcing the use of mypy error codes (
# type: ignore[error-code]
) with flake8-type-ignore.
TF2.7 is now supported (#338)
📝 Documentation
Added back analytic continuation notebook (#312)
Added Zenodo DOI badge (#326)
Added Conda install instructions and Conda badge (#333)
Links to Binder and Colab now point to the branch that corresponds to the version of the documentation (#339)
- docs: pin more intersphinx pages
- fix: correct intersphinx links that were not previously checked
- fix: exclude version 'module' from API
- fix: move docstrings from init to class definition
- refactor: get intersphinx version through function
- style: capitalize conf.py global vars that are no Sphinx options
Intersphinx pages now link to the pinned versions of dependency websites (#339)
🖱️ Developer Experience
Embeded Zenodo metadata (#329)
Fixed comment syntax in .flake8 (#334)
The .flake8
config file was using not using the same comment style as described in
https://flake8.pycqa.org/en/latest/user/configuration.html#project-configuration
Consequence not all errors were identified anymore.
TensorWaves 0.3.3
See all documentation for this version here.
💡 New features
Upgraded to TensorFlow v2.6 (#320)
📝 Documentation
Documentation pages are wider (#316)
Embeded GPLv3+ license file (#318)
Some platforms like Zenodo and conda-forge require the license file to be packaged.
Extended package description in README (#319)
Added package description for PyPI (#324)
Closes ComPWA/compwa.github.io#61
Automated changes by create-pull-request GitHub action
🔨 Internal maintenance
Removed mdit-py-plugins version limit (#313)
🖱️ Developer Experience
Switched to pre-commit.ci where possible (#321)
See ComPWA/qrules#87
Note #309 (comment). This comment is still relevant.
TensorWaves 0.3.2
TensorWaves 0.3.1
TensorWaves 0.3.0
See all documentation for this version here.
💡 New features
Implemented FitResult.count_number_of_parameters (#291 and #297)
Closes #290
Added a method FitResult.count_number_of_parameters()
Constructor arguments of FitResult are now validated (#291)
Mapping of parameters values/errors in FitResult are now 'pretty printed' (#291)
FitResult(
minimum_valid=True,
execution_time=2.9841978549957275,
function_calls=166,
estimator_value=-7579.247627538372,
parameter_values={
'm_f(0)(980)': 0.989885368944097,
'Gamma_f(0)(980)': 0.060228379644260165,
},
parameter_errors={
'm_f(0)(980)': 0.0010628340144144574,
'Gamma_f(0)(980)': 0.0016523232241513362,
},
)
⚠️ Interface
Module interfaces has been renamed to interface (#293)
Removed ReactionInfo from data interface (#294)
Removes AmpForm/QRules's ReactionInfo
from the main interface
. This makes generate_phsp
and generate_data
a bit more clumsy in usage, but the benefit is that ampform
is not imported into TensorWaves's interface
module.
Remove physics module (#299)
Use HelicityModel.sum_components
instead.
TensorWaves now requires AmpForm v0.10.x (#296)
🔨 Internal maintenance
Switched to type alias ParameterValue where possible (#291)
Using type alias ParameterValue
where possible instead of Union[...]
.
📝 Documentation
AIC and BIC example provided in documentation (#291)
Documentation now shows how to generate a deterministic sample (#295)
Show how to generate a deterministic data and phase space sample in step 2 of the documentation.