Skip to content
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

Provide a mechanism for defining simulator-only implementations of callables designed to be intrinsic for code generation #1483

Open
swernli opened this issue May 6, 2024 · 9 comments · May be fixed by #1484
Assignees
Labels
enhancement New feature or request needs triage

Comments

@swernli
Copy link
Collaborator

swernli commented May 6, 2024

Today, a user can provide an implementation (or decomposition) for an operation that they want to simulate and get that same implementation at code generation time (assuming it follows the restrictions for their chosen target) OR they can define the callable as body intrinsic and have it generated as an extern that must be supported by the chosen codegen target. If the user chooses the latter, they get their desired codegen behavior but cannot simulate their program, while the former works for simulation but may prevent QIR codegen or include undesired decomposition.

Given that, it has come up across several discussions that it would be convenient to have a mechanism whereby users could denote a callable as intrinsic for the purpose of codegen but still provide an implementation that gets used during simulation. What form this takes and how it is used in the language are up for discussion, though one possible approach could be a specialized attribute that denotes a callable that should be treated this way.

@swernli swernli added enhancement New feature or request needs triage labels May 6, 2024
@swernli swernli self-assigned this May 6, 2024
@swernli swernli linked a pull request May 6, 2024 that will close this issue
@swernli
Copy link
Collaborator Author

swernli commented May 6, 2024

The linked PR is one possible approach, but we can use this issue to discuss alternatives!

@DmitryVasilevsky
Copy link
Contributor

I'm a bit concerned that just one attribute makes distinction kind-of implicit. When we have two implementations for two different profiles, we see that there're two implementations. Would it be more explicit if we have to implementations - one spelled out and one intrinsic, and decorate those for use in different cases?

@msoeken
Copy link
Member

msoeken commented May 7, 2024

I can see this to be helpful beyond code generation. Maybe the attribute could be SimulatableIntrinsic and the implementation is only used by the simulator but intrinsic for all other evaluation backends.

@swernli
Copy link
Collaborator Author

swernli commented May 7, 2024

I'm a bit concerned that just one attribute makes distinction kind-of implicit. When we have two implementations for two different profiles, we see that there're two implementations. Would it be more explicit if we have to implementations - one spelled out and one intrinsic, and decorate those for use in different cases?

The reason I lean toward keeping them in one has to do with how we compile. If I have two definitions of a callable with the same name in the same scope, it produces a duplicate definition error. The way that works with @Config today is that the attribute forces one of those to be conditionally compiled out based on compilation target. We can't do that with a simulator because simulation is not a compilation target; you can be compiling for "Unrestricted" or "Base" and they both work with simulation. There might be ways to do some automatic implied target switching based on the scenario/feature we are compiling for, but I think there is other overhead to consider like whether both need to have doc comments and the behavior of things like go to definition... overall I prefer having a single item in this case.

@swernli
Copy link
Collaborator Author

swernli commented May 7, 2024

I can see this to be helpful beyond code generation. Maybe the attribute could be SimulatableIntrinsic and the implementation is only used by the simulator but intrinsic for all other evaluation backends.

I debated on the naming in the naming quite a bit in the linked PR... I used CodeGenIntrinsic but I think SimulatableIntrinsic could also work. The key thing I want to think of is how we would document the string and what the name would imply to someone who hasn't read the documentation. On the one hand, CodeGen describes when it's treated as intrinsic, but relies on knowing the shorthand for "code generation" and doesn't quite capture the fact that it's also intrinsic for circuits and resource estimation. Simulatable is also descriptive, but feels like an awkward term for some reason (that might just be in my head). I'm eager to hear what others think of the term.

@swernli
Copy link
Collaborator Author

swernli commented May 7, 2024

Another option that is possible but would require some more work in updating the parser is to have it not be attribute based at all but rather extend the existing body intrinsic generator to allow for a block. So we would support both the existing:

operation MyGate(q : Qubit) : Unit {
    body intrinsic;
}

and additionally support:

operation MyGate(q : Qubit) : Unit {
    body intrinsic {
        // Put simulator-only implementation here.
    }
}

While that might be a neat syntactic trick, I don't think it's as descriptive as having an attribute which at least provides a string for the user to search for in docs.

@swernli
Copy link
Collaborator Author

swernli commented May 11, 2024

A few more points that have come up in discussion over the last week:

  • Another benefit of attribute vs new "body" syntax is that it's easier to quickly turn it off and on, as you only need to add/remove or comment/uncomment one line.
  • @minestarks added a +1 to the suggestion from @msoeken to use a name that is more specific to simulation, since that's what the implementation is used for.

Given these two, I want to focus in on finding a good attribute name. Here's some we have brainstormed so far, would love to hear some more!

  1. SimulatableIntrinsic
  2. SimulationFallback
  3. SimulationOnly
  4. SimImpl

@msoeken
Copy link
Member

msoeken commented May 13, 2024

Given these two, I want to focus in on finding a good attribute name. Here's some we have brainstormed so far, would love to hear some more!

  1. SimulatableIntrinsic
  2. SimulationFallback
  3. SimulationOnly
  4. SimImpl

I don't have more suggestions. I think all of them are very descriptive, but SimulationOnly could indicate that this operation cannot be used anywhere else except for simulation.

@minestarks
Copy link
Member

  • Another benefit of attribute vs new "body" syntax is that it's easier to quickly turn it off and on, as you only need to add/remove or comment/uncomment one line.

@swernli I don't mind the attribute, but I will quibble with this... commenting out the @NameTBD() attribute has the same effect as commenting out body intrinsic in the hypothetical new syntax. Both are a one-line change.

I like SimulatorOnly.

FWIW I also like the idea of just reusing the @Config() attribute for this, and call it @Config(Simulator) . Yes we'd have to make a special case for it but I feel like we've taken enough liberties with how we implemented @Config() that I don't think this feels like a reach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request needs triage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants