-
Notifications
You must be signed in to change notification settings - Fork 7
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
test: serialisation round trip testing for OpDef
#999
Conversation
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.
The schema changes look good to me, I'm just a bit confused with the introduction of ConfiguredBaseModel
in #982
@classmethod | ||
def set_model_config(cls, config: ConfigDict): | ||
cls.model_config = config.copy() | ||
cls.model_config["extra"] = "allow" | ||
|
||
class Config: | ||
json_schema_extra = { | ||
"required": ["c"], | ||
} |
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.
I'm a bit confused with ConfiguredBaseModel
, why do we need this?
I would have expected something like
class CustomConst(BaseMode, extra=Extra.allow):
c: str
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.
The ConfiguredBaseModel
let's us generate multiple schemas with different settings. Unfortunately, those settings override the config you set up in the class. I suppose your suggestion would work (using BaseModel
). It would not pick up any other (i.e. non-extra) config (e.g. strict = True, although I'm not sure that does anything) which I think would be very confusing if anyone ever used model_rebuild
with more config.
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.
But I am about to push changes here, which make this discussion moot.
c223a56
to
c40b546
Compare
74c6797
to
507d9c0
Compare
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.
Generally looks good, a few thoughts on OpDefs
hugr/src/extension/op_def.rs
Outdated
} = &other.0; | ||
|
||
let get_sig = |sf: &_| match sf { | ||
// if SignatureFunc or CustomValidator are changed we should get |
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.
Is this a TODO or a description of what happens now? I don't think there is much we can do about changes to validators or custom binary signature-funcs, but we can't serialize those anyway....this looks good for serialization tests
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 can't serialize them YET, but if we make them traits we can serialize them as we do CustomConst
. This comment as intended to help people keep it correct when fields are added to CustomValidator
.
hugr/src/extension/op_def.rs
Outdated
&& misc == other_misc | ||
&& get_sig(signature_func) == get_sig(other_signature_func) | ||
&& get_lower_funcs(lower_funcs) == get_lower_funcs(other_lower_funcs) | ||
&& constant_folder.is_none() |
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.
If we serialize an OpDef with a constant folder, what do we expect to get back in the roundtrip? Might be worth a comment on these last two lines, or (if this code is used only for roundtrip testing) even an assert that they are none
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.
Did you mean to do something here other than thumbs-up ?
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.
Yes, I've added a comment
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #999 +/- ##
==========================================
+ Coverage 86.78% 86.88% +0.10%
==========================================
Files 91 91
Lines 18560 18697 +137
Branches 18167 18304 +137
==========================================
+ Hits 16107 16245 +138
+ Misses 1606 1603 -3
- Partials 847 849 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
4d4fe77
to
5305fd2
Compare
99c3fd2
to
950679c
Compare
This is ready for review, but it's based on #981 so must wait for that to be merged. |
950679c
to
86e5e11
Compare
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.
Generally great ;-) (so yes that's even better than last time!). I think there's a bug in ConstInt64, and some minor suggestions of renames etc. for readability but looks good to me. Thanks @doug-q !
hugr-core/src/extension/op_def.rs
Outdated
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { | ||
use crate::proptest::{any_serde_yaml_value, any_smolstr, any_string}; | ||
use proptest::collection::{hash_map, vec}; | ||
let signature_func: BoxedStrategy<SignatureFunc> = any::<SignatureFunc>(); |
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.
super-nit: I'd inline signature_func
and lower_func
, they are barely shorter than their definitions
hugr-core/src/ops/constant.rs
Outdated
3, // No more than 3 branch levels deep | ||
32, // Target around 32 total elements | ||
3, // Each collection is up to 3 elements long | ||
|element| { |
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.
element
-> child
maybe? It's the recursive call right?
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.
You could, this is copy-pasted from the docs though.
hugr-core/src/ops/constant.rs
Outdated
3, // Each collection is up to 3 elements long | ||
|element| { | ||
(Type::any_non_row_var(), vec(element.clone(), 0..3)).prop_map( | ||
|(typ, contents)| { |
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.
and contents
is the result of that recursive call (so elem_strat
and elem
, perhaps, or child_strat
and child
?)
hugr-core/src/ops/constant/custom.rs
Outdated
let typ = any::<Type>(); | ||
let extensions = any::<ExtensionSet>(); | ||
let value = (any_serde_yaml_value(), any_string()).prop_map(|(value, c)| { | ||
[("c".into(), c.into()), ("v".into(), value)] |
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.
Is it plausible to break this lambda |(value, c)| ....
out into a function with a name and a type signature? It feels like it could be an any_something_with
function (_with
as it takes a couple of parameters)
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.
Not quite sure what you mean. I don't think you can extract anything useful here. Happy to add a comment to explain what's going on.
let signed_strat = (..=LOG_WIDTH_MAX).prop_flat_map(|log_width| { | ||
use i64; | ||
let max_val = (2u64.pow(log_width as u32) / 2) as i64; | ||
let min_val = -max_val - 1; |
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.
Hang on. So let's take log_width == 5
. Then max_val = 2u64.pow(5)/2
i.e. 16
. min_val
is therefore -17
. You're then creating a value in range -17..16
...
I'd not expect Self::new_s
to be happy if you generated -17
or 16
though. But maybe you're not hitting this? I tried copying your max_val
and min_val
computation into a separate test and that lead me tothink my interpretation was correct...
(So, consider: rename max_val
to max_valp1
; then let min_val = -max_valp1
; then use min_val..<max_valp1
)
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.
Yeah this doesn't make sense, will double check what's going on.
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.
I've rewritten, and added a proptest that convinces me that it's now correct.
Co-authored-by: Alan Lawrence <alan.lawrence@quantinuum.com>
hugr-core/src/extension/op_def.rs
Outdated
@@ -474,12 +474,14 @@ impl Extension { | |||
} | |||
|
|||
#[cfg(test)] | |||
mod test { | |||
pub mod test { |
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.
super-nit: pub(super)
might have less possibility of misleading the reader
|
||
impl SimpleOpDef { | ||
pub fn new(op_def: OpDef) -> Self { | ||
assert!(op_def.constant_folder.is_none()); |
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.
Nice! I was going to comment before, that SimpleOpDef
was actually OpDefEqualityWrapper
and the "simple" only came from the impl Arbitrary for
, but this enforces simplicity, like it :)
32, // Target around 32 total elements | ||
3, // Each collection is up to 3 elements long | ||
|child_strat| { | ||
(Type::any_non_row_var(), vec(child_strat, 0..3)).prop_map( |
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.
That bit of renaming helps a lot here I think, thanks :)
hugr-core/src/ops/constant/custom.rs
Outdated
// The "c" and "v" come from the `typetag::serde` annotation on | ||
// `trait CustomConst`. | ||
// TODO This is not ideal, if we were to randomly | ||
// generate a valid tag(e.g. "c" = "ConstInt") then things will |
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.
// generate a valid tag(e.g. "c" = "ConstInt") then things will | |
// generate a valid tag (e.g. "ConstInt") then things will |
...in that the "c" =
is not part of the tag. But the idea is that we are relying on the random any_string
not matching any handler for a recognized type, right?
Perhaps change randomly
on previous line to accidentally
, and/or ...then the handler for that type will interpret the "v" and fail
fn any_signed_int_with_log_width() -> impl Strategy<Value = (u8, i64)> { | ||
(..=LOG_WIDTH_MAX).prop_flat_map(|log_width| { | ||
let width = 2u64.pow(log_width as u32); | ||
let max_val = ((1u64 << (width - 1)) - 1u64) as i64; |
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.
👍
Co-authored-by: Alan Lawrence <alan.lawrence@quantinuum.com>
OpDef
OpDef
## 🤖 New release * `hugr`: 0.5.0 -> 0.5.1 * `hugr-core`: 0.1.0 -> 0.2.0 * `hugr-passes`: 0.1.0 -> 0.2.0 * `hugr-cli`: 0.1.0 -> 0.1.1 <details><summary><i><b>Changelog</b></i></summary><p> ## `hugr` <blockquote> ## 0.5.1 (2024-06-07) ### Refactor - Move binary to hugr-cli ([#1134](#1134)) </blockquote> ## `hugr-core` <blockquote> ## 0.2.0 (2024-06-07) ### Bug Fixes - [**breaking**] Validate that control-flow outputs have exactly one successor ([#1144](#1144)) - Do not require matching extension_reqs when creating a replacement ([#1177](#1177)) ### Features - Add `ConstExternalSymbol` to prelude ([#1123](#1123)) - `HugrView::extract_hugr` to extract regions into owned hugrs. ([#1173](#1173)) ### Testing - Serialisation round trip testing for `OpDef` ([#999](#999)) </blockquote> ## `hugr-passes` <blockquote> ## 0.2.0 (2024-06-07) ### Features - Add `ValidationLevel` tooling and apply to `constant_fold_pass` ([#1035](#1035)) </blockquote> ## `hugr-cli` <blockquote> ## 0.1.1 (2024-06-07) ### Features - Reexport `clap::Parser` and `clap_verbosity_flag::Level` from hugr_cli ([#1146](#1146)) ### Refactor - Move binary to hugr-cli ([#1134](#1134)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/MarcoIeni/release-plz/).
We also add coverage for roundtripping
CustomSerialized
which was omitted from the previous PR.