-
Notifications
You must be signed in to change notification settings - Fork 16
feat: Decorator to auto lower to hugr extension #1091
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
Open
hsemenenko
wants to merge
18
commits into
main
Choose a base branch
from
hs/auto_lowering
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
8530151
Decorator to auto lower to hugr extension
hsemenenko 877d09a
Clean up hugr exts
hsemenenko da0b7cd
Fix mypy errors
hsemenenko f5ebafd
Merge branch 'main' into hs/auto_lowering
hsemenenko 45bb502
Merge branch 'main' into hs/auto_lowering
hsemenenko 1e97734
Merge branch 'main' into hs/auto_lowering
hsemenenko ba99174
Merge branch 'main' into hs/auto_lowering
hsemenenko 02857ce
Merge branch 'main' into hs/auto_lowering
hsemenenko eab5c0a
Move decorator to guppy-internals
hsemenenko 9ef075b
Fix mypy warning
hsemenenko 9be5653
Fix ruff warning
hsemenenko 99a7bd4
Merge branch 'main' of https://github.com/CQCL/guppylang into hs/auto…
hsemenenko 3a671ec
Create new type for lowerable functions
hsemenenko 6430e6e
Get type signature from compiled hugr and add op to hugr extension in…
hsemenenko 02fdcba
Test multiple operations in single program. Add test that op is added…
hsemenenko 8f3927a
Remove unused imports
hsemenenko b8dfebf
Merge branch 'main' of https://github.com/CQCL/guppylang into hs/auto…
hsemenenko 1aea324
Update docs and signature argument usage
hsemenenko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
guppylang-internals/src/guppylang_internals/definition/lowerable.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from dataclasses import dataclass | ||
from typing import TYPE_CHECKING | ||
|
||
from guppylang_internals.compiler.core import ( | ||
GlobalConstId, | ||
) | ||
from guppylang_internals.definition.custom import ( | ||
CustomFunctionDef, | ||
RawCustomFunctionDef, | ||
) | ||
from guppylang_internals.span import SourceMap | ||
from guppylang_internals.tys.ty import ( | ||
FunctionType, | ||
NoneType, | ||
) | ||
|
||
if TYPE_CHECKING: | ||
from guppylang_internals.checker.core import Globals | ||
|
||
|
||
@dataclass(frozen=True) | ||
class RawLowerableFunctionDef(RawCustomFunctionDef): | ||
"""A raw custom function definition provided by the user. | ||
|
||
Custom functions provide their own checking and compilation logic using a | ||
`CustomCallChecker` and a `CustomCallCompiler`. | ||
|
||
The raw definition stores exactly what the user has written (i.e. the AST together | ||
with the provided checker and compiler), without inspecting the signature. | ||
|
||
Args: | ||
id: The unique definition identifier. | ||
name: The name of the definition. | ||
defined_at: The AST node where the definition was defined. | ||
call_checker: The custom call checker. | ||
call_compiler: The custom call compiler. | ||
higher_order_value: Whether the function may be used as a higher-order value. | ||
signature: Optional User-provided signature. | ||
""" | ||
|
||
def parse(self, globals: "Globals", sources: SourceMap) -> "CustomFunctionDef": | ||
"""Parses and checks the signature of the lowerable function. | ||
|
||
The signature is optional if custom type checking logic is provided by the user. | ||
However, a signature *must* be provided to use the function as a higher-order | ||
value (either by annotation or as an argument). If a signature is provided as an | ||
argument, this will override any annotation. | ||
|
||
If no signature is provided, we fill in the dummy signature `() -> ()`. This | ||
type will never be inspected, since we rely on the provided custom checking | ||
code. The only information we need to access is that it's a function type and | ||
that there are no unsolved existential vars. | ||
""" | ||
from guppylang_internals.definition.function import parse_py_func | ||
|
||
func_ast, _ = parse_py_func(self.python_func, sources) | ||
sig = self.signature or self._get_signature(func_ast, globals) | ||
ty = sig or FunctionType([], NoneType()) | ||
return CustomFunctionDef( | ||
self.id, | ||
self.name, | ||
func_ast, | ||
ty, | ||
self.call_checker, | ||
self.call_compiler, | ||
self.higher_order_value, | ||
GlobalConstId.fresh(self.name), | ||
sig is not None, | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from guppylang import guppy | ||
from guppylang_internals.decorator import lowerable_op | ||
from guppylang.std.quantum import qubit, h, cx, measure | ||
|
||
import hugr.ext as he | ||
|
||
from pydantic_extra_types.semantic_version import SemanticVersion | ||
|
||
|
||
def test_auto_hugr_lowering(validate): | ||
test_hugr_ext = he.Extension("test_hugr_ext", SemanticVersion(0, 1, 0)) | ||
|
||
@lowerable_op(test_hugr_ext) | ||
def entangle(q0: qubit, q1: qubit) -> None: | ||
h(q0) | ||
cx(q0, q1) | ||
|
||
hsemenenko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@guppy | ||
def main() -> None: | ||
q0 = qubit() | ||
q1 = qubit() | ||
q2 = qubit() | ||
entangle(q0, q1) | ||
hsemenenko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
entangle(q1, q2) | ||
measure(q0) | ||
measure(q1) | ||
measure(q2) | ||
|
||
hugr = main.compile() | ||
|
||
hugr.extensions.append(test_hugr_ext) | ||
hsemenenko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
validate(hugr) | ||
|
||
|
||
def test_lower_funcs_hugr(validate): | ||
test_hugr_ext = he.Extension("test_hugr_ext", SemanticVersion(0, 1, 0)) | ||
|
||
@lowerable_op(test_hugr_ext) | ||
def entangle(q0: qubit, q1: qubit) -> None: | ||
h(q0) | ||
cx(q0, q1) | ||
|
||
op = test_hugr_ext.get_op("entangle") | ||
|
||
for funcs in op.lower_funcs: | ||
validate(funcs.hugr) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Hmmmm, ok. So the differences against the
RawCustomFunctionDef.parse
that we're overriding here are:self.signature
before we callself._get_signature(func_ast, globals)
....is that right?docstring
that AFAICS in the original/overridden method is defined but not used(?!)There is definitely an opportunity here for both commoning-up, and possibly cleaning up....do you feel like taking it?
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, these are the difference between the two methods. As suppressing the error if there is no body is required for the lowering case, it was suggested that these implementations were kept separate. This does come with a small side affect that
self.signature
is not used.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, agreed that you need suppress the warning, and since you are now using
self.signature
, looks good to me. You could possibly add a private helper that does thesig = .....; ty = .....; return CustomFunctionDef(self...., self....) etc.
(taking justself
andfunc_ast
as parameters) but fine as it stands.