Soquet to _Soquet, _QVar, Soquet and QVar#1831
Soquet to _Soquet, _QVar, Soquet and QVar#1831mpharrigan wants to merge 7 commits intoquantumlib:mainfrom
Conversation
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant and well-executed refactoring of the Soquet data model, separating it into _Soquet for graph nodes and _QVar for mutable builder variables. This improves the separation of concerns and maintainability. The backward compatibility shims using protocols and metaclasses are clever and should ease the transition for existing code. The improved error messages are also a great addition. I've found one issue regarding a missing type hint that should be addressed, which aligns with the guideline that type annotations should document intended types.
qualtran/_infra/composite_bloq.py
Outdated
| ] | ||
| return soq_map | ||
|
|
||
| def add_from(self, bloq: Bloq, **in_soqs: SoquetInT): |
There was a problem hiding this comment.
The return type annotation for this method is missing. The implementation returns a tuple of soquets, but the signature implies it returns None. This is inconsistent with add_t and how add_from is used in flatten_once.
The previous signature was -> Tuple[SoquetT, ...]. The new signature should likely be -> Tuple['QVarT', ...], or potentially use the same return type logic as add() if a single value or None can be returned.
| def add_from(self, bloq: Bloq, **in_soqs: SoquetInT): | |
| def add_from(self, bloq: Bloq, **in_soqs: SoquetInT) -> Tuple['QVarT', ...]: |
References
- Type annotations should document the intended type, including return types, to clarify the contract of the function.
There was a problem hiding this comment.
you're right, robot. I suspect at one point I wanted to make this follow the same return type logic as add() but not in this PR!
In Qualtran, we compose quantum operations into larger operations by connecting the outputs of a predecessor bloq to the input "ports" of a successor bloq. We've used the
Soquetfrozen attrs class to represent these nodes in the compute graph, which address the "ports" of a particular instance of the bloq.Previously, the immutable
Soquetobject represented both the "quantum variables" being passed around during bloq building as well as the nodes of the compute graph. With this PR, these concerns are separated. The compute graph nodes are frozen dataclasses of type_Soquet, and the quantum variables are mutable objects of type_QVar. We will put additional helper attributes and methods onto_QVarto assist in bloq building.For backwards compatibility, the
Soquetname is now atyping.Protocolthat encapsulates the duck-typing behavior of_Soquetand_QVar. Bloqs in the wild should not have to update the type annotations inbuild_composite_bloqwith this backwards compatibilty typing shim.
isinstance(..., Soquet)checks will emit a deprecation warning and return True for either_Soquetor_QVar.If you're using isinstance(soq, Soquet) to determine whether an item is a single object
or an ndarray of those objects, use
BloqBuilder.is_single(x)orBloqBuilder.is_ndarray(x). See the documentation inQVarTfor an example.If you're developing library functionality, you can port isinstance checks to either
_SoquetorQVaras appropriate.Backwards compatibility note: Despite the fundamental change to the data model, this PR is designed to be runtime-backwards compatible with deprecation warnings. The way I've accomplished this is through some dark Python incantations, so no guarantees. Please send reports if this breaks something.
Note that type checkers like
mypywill likely still complain about things even if the code runs fine without modification following this PR.High-priority deprecations
Soquets yourself. You really shouldn't have been doing this._Soquetis now "private"CompositeBloqby iterating over connections and usingmap_soqs, please urgently upgrade your code to use the new idiom where you must initialize the mapping withbb.initial_soq_map. The shim I put in is brittle. BloqBuilder.map_soqs behavior when soq is not in map #1742