A target package is intended to provide the core functionality of the callables in the Microsoft.Quantum.Intrinsic namespase specialized to a particular hardware or software (simulator) target. Not every target natively supports the same set of callables, so the expected pattern for adapting them to the Q# API is via the package that defines the set of natively supported callabes (defined as body intrinsic
in Q#) and the set of decompositions in Q# that implemenent the remainder of the API via the subset of native callables.
Each target package is comprised of a subset of body intrinsic
Q# definitions, drawn from the TargetDefinitions/Intrinsic folder, along with the necessary decomposition implementations from TargetDefinitions/Decompositions folder to sufficiently implement the remainder of the Microsoft.Quantum.Intrinsic API surface. Each intrinsic or decomposed callable is kept in a separate file to allow for easier reuse and recombination across packages. The individual package defines the subset files that should be compiled together into the package via a .props file in the TargetDefinitions/TargetPackages folder. That file acts as an easy reference for understanding which callabes are native to that target and which decompositions each target uses. As support for new targets is added, they can reuse existing intrinsic or decomposition definitions in a new combination and/or introduce new callables (some of which may be internal for use in decompositions only) that correspond to taret-specific capabilities. The goal for any target package is that each callabe that shares a name with a publicly defined API (such as X
or Measure
) will have the same signature and API contract even though the details of each implementaiton may vary. That way even if different targets have different capabilities, the core set of Q# gates functions the same across all targets (with allowances for increased complexity or resource utilization in a given decomposition).
In addition, this folder defines an interfaces package that targets can use to attach their specific implementation of native callables to a runtime. Here, the interfaces package represents the union of all body intrinsic
Q# callabes across all targets, which each callable having it's own unique API surface. Then the combined interface representing a particular target is a union of the interfaces required to implement the set of native supported callabes on that target. For example, IQSharpCore is the interface that combines the set of specific gate interfaces representing the natively supported gates of the QSharp.Core target, and any target that wants to support execution with the QSharpCore package would need to implement that interface. By implementing multiple interfaces, like our simulator does, a target can support multiple target packages without having to recompile or take a direct dependency on any specific target. Long term, we expect the indirection provided by these interfaces to be part of the code that is auto-generated from the Q# declatation witohut requiring any manual additions to the interfaces package.