feat: add methods to apply rewriter instructions to resources in routines#239
feat: add methods to apply rewriter instructions to resources in routines#239Brendan-Reid1991 merged 285 commits intomainfrom
Conversation
…ing and improved descriptions
…ork for all backends
* docs: Added the list of possible values for `ResourceType` and `PortDirection` on docstring * docs: Added missing `Raises` sections in existing docstrings * docs: Improved styling of function segments in docs for easy navigation * docs: Added clickable reference links to parts of documentations in doc strings * fix: Fixed the formatting and lint issues * fix(docs): Fixed docs reference issues on`_compile.py`, `_evaluate.py` & `_routine.py` * fix: Exposed `SymbolicBackend` through `bartiq.symbolics` * fix: Exposed `Port` at top level (`bartiq.Port`) * docs: Adding doc-string for `Port` class * fix(docs): Added missing Args, and references in modified docs * fix(docs): Added External references * fix(docs): Fixed issues of long `Return` descriptions * fix(docs): Reverting `symbolics` concept markdown content * fix(docs): Improved styling of overload functions displayed in docs & removed type hints for `postorder_transform` * fix(docs): Fixed a formatting issue in the module doc-string * fix(docs): Removed `SymbolicBackend` from exposing to top-level, and added submodule rendering and extra styling for documentation * fix(docs): Removed unnecessary doc-strings in each `postorder_transform` overload function * fix(docs): Extended `module` & `method` annotations in docs
…bout interactive tools
… + transitive resources
| return {"name": name, "resources": [{"name": "dummy", "type": "additive", "value": f"max(0, {name})"}]} | ||
|
|
||
|
|
||
| b = routine("b") |
There was a problem hiding this comment.
[minor] IMO it would be clearer and more consistent with rest of tests if we would actually just put an explicit dictionary here?
There was a problem hiding this comment.
yes, probably!
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| """Routine rewriters allow you to rewrite expressions across entire routines.""" |
There was a problem hiding this comment.
[nitpick] I think it should be Resource rewriters now, no?
| routine = deepcopy(self.routine) | ||
|
|
||
| def _traverse_routine(routine: CompiledRoutine) -> CompiledRoutine: | ||
| """Recursively traverse the routine, replacing resource values | ||
| starting from the lowest level of children.""" | ||
| for _name, child_routine in routine.children.items(): | ||
| routine.children[_name] = _traverse_routine(child_routine) | ||
| if self.resource in routine.resources and not isinstance( | ||
| routine.resource_values[self.resource], (int | float) | ||
| ): | ||
| return replace( | ||
| routine, | ||
| resources=routine.resources | ||
| | { | ||
| self.resource: replace( | ||
| routine.resources[self.resource], | ||
| value=_update_expression( | ||
| self.rewriter_factory, | ||
| cast(T, routine.resources[self.resource].value), | ||
| self.rewriter.history(), | ||
| ), | ||
| ) | ||
| }, | ||
| ) | ||
|
|
||
| return routine |
There was a problem hiding this comment.
suggestion: There is no need for a deepcopy here. Observe that:
- Updating of resources does not involve reading from children
- Therefore, it doesn't matter if we have updated children or not when we are updating resources.
So, we can just store children and just update them when we do replace.
Even better, we already have similar transformations in other places like preprocessing, and we have a decorator called @postorder_transform that you can use to simplify this piece of code.
| root = { | ||
| "name": "root", | ||
| "children": [ | ||
| { | ||
| "name": "a", | ||
| "children": [ | ||
| {"name": "b", "resources": [{"name": "dummy", "type": "additive", "value": "max(0, b)"}]}, | ||
| {"name": "c", "resources": [{"name": "dummy", "type": "additive", "value": "max(0, c)"}]}, | ||
| ], | ||
| }, | ||
| { | ||
| "name": "x", | ||
| "children": [ | ||
| {"name": "y", "resources": [{"name": "dummy", "type": "additive", "value": "max(0, y)"}]}, | ||
| {"name": "z", "resources": [{"name": "dummy", "type": "additive", "value": "max(0, z)"}]}, | ||
| ], | ||
| }, | ||
| ], | ||
| } | ||
| compiled = compile_routine( | ||
| Routine.from_qref(root, _SYMPY_BACKEND), compilation_flags=CompilationFlags.EXPAND_RESOURCES | ||
| ).routine |
There was a problem hiding this comment.
suggestion: Given some fields are mutable in both routine and compiled routine, I think that it would be much more safe to make those two variables into function-scoped fixtures.
Description
rewriters/expression.pynow contains the base classrewriters/sympy_rewriter.pynow contains theSympyExpressionRewriterand the factory methodrewriters/resources.pynow containsResourceRewriterI also want to settle on names for classes/files in this PR! So make your objections heard here!
Potential issues
ResourceRewriterforwards attribute calls ton therewriterattribute, and theroutineattribute is not modified by instruction calls, only the rewriter is.apply_to_entire_routinepushes all the instructions through every level of the routine, and returns a new CompiledRoutine object.ExpressionRewritersandResourceRewritersExpressionRewriterreturn a newExpressionRewriterinstance, the same is not true forResourceRewritersExpressionRewriteron aResourceRewriterupdates therewriterattribute, but the class instance remains the same.VS
That is, the
ResourceRewriterinstance is updated in-place, whereas theExpressionRewriteris not.Please verify that you have completed the following steps