-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add a schema for serialization #105
Changes from all commits
598ffda
68c0c5e
a22613b
ab100c7
cb5afce
cc6028a
da4d16a
0fcb3c8
3530965
020c8f5
84272b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Serialization | ||
|
||
|
||
## Introduction | ||
|
||
Histogram serialization has to cover a wide range of formats. As such, we | ||
describe a form for serialization that covers the metadata structure as | ||
JSON-like, with a provided JSON-schema. The data (bins and/or variable edges) | ||
is stored out-of-band in a binary format based on what type of data file you | ||
are in. For very small (primarily 1D) histograms, data is allowed inline as | ||
well. | ||
|
||
The following formats are being targeted: | ||
|
||
``` | ||
┌────────┐ ┌────────┐ ┌───────┐ | ||
│ ROOT │ │ HDF5 │ │ ZIP │ | ||
└────────┘ └────────┘ └───────┘ | ||
``` | ||
|
||
Other formats can be used as well, assuming they support out-of-band data and | ||
text attributes or files for the metadata. | ||
|
||
## Caveats | ||
|
||
This structure was based heavily on boost-histogram, but it is intended to be | ||
general, and can be expanded in the future as needed. As such, the following | ||
limitations are required: | ||
|
||
* Serialization followed by deserialisation may cause axis changes. Axis types | ||
may change to an equivalent but less performant axis, growth status will be | ||
lost, etc. | ||
* Metadata must be expressible as JSON. It should also be reasonably sized; some | ||
formats like HDF5 may limit the size of attributes to 64K. | ||
* Floating point errors could be incurred on conversion, as the storage format | ||
uses a stable but different representation. | ||
* Axis `name` is only part of the metadata, and is not standardized. This is | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be a very welcome addition, at least in HS3 we will rely on the name of variables in order to match data and function evaluation inputs (both standards, in principle, don't need to agree, but it would be great of course if they could). How would Hist handle this? Just as before, taking the name from the label? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would store the names in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you remind me what is lacking in support from boost-histogram? The metadata field of the axis was originally just intended to be a name. @henryiii pushed for it to be a general Python type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The metadata stores the name, title, all ROOT metadata, etc. There are no requirements on it, except that it be a string-keyed dictionary. It would be nice to have an optional "name" slot which was guaranteed to be a unique string that can be used to refer to the the axis if present. One of the common themes at PyHEP.dev was a desire to avoid ever writing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this nearly leads to a slightly different discussion, but metadata can indeed be helpful. I would disect it into two parts:
To go back specifically to BH and serialization:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hist will look for We could bake it into the standard instead, and then hist's job gets easier, while boost-histogram's job gets harder. Boost-histogram would have to have some way to handle names - currently this packing/unpacking is in Hist, so it's a little harder. That also could be done, so it's really a case of picking what's best for everyone else. |
||
due to lack of support from boost-histogram. | ||
|
||
## Design | ||
|
||
The following axes types are supported: | ||
|
||
* `"regular"`: A regularly spaced set of even bins. Boost-histogram's "integer" | ||
axes maps to this axis as well. Has `upper`, `lower`, `bins`, `underflow`, | ||
henryiii marked this conversation as resolved.
Show resolved
Hide resolved
|
||
`overflow`, and `circular` properties. `circular` defaults to False if not | ||
present. | ||
* `"variable"`: A continuous axis defined by bins+1 edges. Has `edges`, which | ||
is either an in-line list of numbers or a string pointing to an out-of-band data source. | ||
Also has `underflow`, `overflow`, and `circular` properties. `circular` | ||
defaults to False if not present. | ||
* `"category_int"`: A list of integer bins, non-continuous. Has `categories`, | ||
which is an in-line list of integers. Also has `flow`. | ||
* `"category_str"`: A list of string bins. Has `categories`, | ||
which is an in-line list of strings. Also has `flow`. | ||
* `"boolean"`: A true/false axis. | ||
|
||
Axes with gaps are currently not supported. | ||
|
||
All axes support `metadata`, a string-valued dictionary of arbitrary, JSON-like data. | ||
|
||
The following storages are supported: | ||
|
||
* `"int"`: A collection of integers. Boost-histogram's Int64 and AtomicInt64 | ||
map to this, and sometimes Unlimited. | ||
* `"double"`: A collection of 64-bit floating point values. Boost-histogram's | ||
Double storage maps to this, and sometimes Unlimited. | ||
* `"weighted"`: A collection of two arrays of 64-bit floating point values, | ||
`"value"` and `"variance"`. Boost-histogram's Weight storage maps to this. | ||
* `"mean"`: A collection of three arrays of 64-bit floating point values, | ||
"count", "value", and "variance". Boost-histogram's Mean storage maps to | ||
this. | ||
* `"weighted_mean"`: A collection of four arrays of 64-bit floating point | ||
values, `"sum_of_weights"`, `"sum_of_weights_squared"`, `"values"`, and | ||
`"variances"`. Boost-histogram's WeighedMean storage maps to this. | ||
|
||
## CLI/API | ||
|
||
You can currently test a JSON file against the schema by running: | ||
|
||
```console | ||
$ python -m uhi.schema some/file.json | ||
``` | ||
|
||
Or with code: | ||
|
||
```python | ||
import uhi.schema | ||
|
||
uhi.schema.validate("some/file.json") | ||
``` | ||
|
||
Eventually this should also be usable for JSON's inside zip, HDF5 attributes, | ||
and maybe more. | ||
|
||
```{warning} | ||
|
||
Currently, this spec describes **how to prepare the metadata** for one of the | ||
targeted backends. It does not yet cover backend specific details, like how to | ||
define and use the binary resource locator strings or how to store the data. | ||
JSON is not a target spec, but just part of the ZIP spec, meaning the files | ||
that currently "pass" the tool above would be valid inside a `.zip` file | ||
eventually, but are not valid by themselves. | ||
``` | ||
|
||
## Rendered schema | ||
|
||
```{jsonschema} ../src/uhi/resources/histogram.json | ||
``` | ||
|
||
|
||
## Full schema | ||
|
||
The full schema is below: | ||
|
||
```{literalinclude} ../src/uhi/resources/histogram.json | ||
:language: json | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For an interchangable standard that is acceptable, but boost-histogram should always have also its own data format were no information is lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still have pickling, which is both stable and lossless. It's just not interchangeable. ;)