public override ResolvedSignature OnSignature(ResolvedSignature s) { if (s.TypeParameters.Any()) { throw new Exception("Signatures cannot contains type parameters"); } return(base.OnSignature(s)); }
public override ResolvedSignature OnSignature(ResolvedSignature s) { // Remove the type parameters from the signature s = new ResolvedSignature( ImmutableArray <QsLocalSymbol> .Empty, s.ArgumentType, s.ReturnType, s.Information); return(base.OnSignature(s)); }
public void ExcludeInaccessible() { var elements = new[] { Access.Public, Access.Internal } .SelectMany(access => { var source = new Source("Tests.qs", QsNullable <string> .Null); var unit = ResolvedType.New(QsType.UnitType); var signature = new ResolvedSignature( Array.Empty <QsLocalSymbol>().ToImmutableArray(), unit, unit, CallableInformation.NoInformation); var argumentTuple = QsTuple <ArgDeclType> .NewQsTuple(ImmutableArray.Create <QsTuple <ArgDeclType> >()); var callable = new QsCallable( kind: QsCallableKind.Operation, fullName: MakeFullName(access + "Operation"), attributes: ImmutableArray <QsDeclarationAttribute> .Empty, access, source: source, location: ZeroLocation, signature: signature, argumentTuple: argumentTuple, specializations: ImmutableArray.Create <QsSpecialization>(), documentation: ImmutableArray.Create <string>(), comments: QsComments.Empty); var typeItems = QsTuple <QsTypeItem> .NewQsTuple( ImmutableArray.Create(QsTuple <QsTypeItem> .NewQsTupleItem(QsTypeItem.NewAnonymous(unit)))); var type = new QsCustomType( fullName: MakeFullName(access + "Type"), attributes: ImmutableArray <QsDeclarationAttribute> .Empty, access, source: source, location: ZeroLocation, type: unit, typeItems: typeItems, documentation: ImmutableArray.Create <string>(), comments: QsComments.Empty); return(new[] { QsNamespaceElement.NewQsCallable(callable), QsNamespaceElement.NewQsCustomType(type) }); }); var emptyLookup = Array.Empty <ImmutableArray <string> >().ToLookup(x => ""); var ns = new QsNamespace(CanonName, elements.ToImmutableArray(), emptyLookup); var docNs = new DocNamespace(ns); var stream = new MemoryStream(); #pragma warning disable 618 // WriteToStream is obsolete. docNs.WriteToStream(stream, null); #pragma warning restore 618 var expected = @"### YamlMime:QSharpNamespace # This file is automatically generated. # Please do not modify this file manually, or your changes may be lost when # documentation is rebuilt. uid: microsoft.quantum.canon name: Microsoft.Quantum.Canon operations: - uid: microsoft.quantum.canon.publicoperation summary: '' newtypes: - uid: microsoft.quantum.canon.publictype summary: '' ... "; var actual = Encoding.UTF8.GetString(stream.ToArray()); Assert.Equal(expected, actual); }
private (ResolvedSignature, IEnumerable <QsSpecialization>) MakeSpecializations( QsQualifiedName callableName, ResolvedType paramsType, SpecializationImplementation bodyImplementation) { QsSpecialization MakeSpec(QsSpecializationKind kind, ResolvedSignature signature, SpecializationImplementation impl) => new QsSpecialization( kind, callableName, ImmutableArray <QsDeclarationAttribute> .Empty, this.CurrentCallable.Callable.SourceFile, QsNullable <QsLocation> .Null, QsNullable <ImmutableArray <ResolvedType> > .Null, signature, impl, ImmutableArray <string> .Empty, QsComments.Empty); var adj = this.CurrentCallable.Adjoint; var ctl = this.CurrentCallable.Controlled; var ctlAdj = this.CurrentCallable.ControlledAdjoint; bool addAdjoint = false; bool addControlled = false; bool isSelfAdjoint = false; if (this.InWithinBlock) { addAdjoint = true; addControlled = false; } else if (this.InBody) { if (adj != null && adj.Implementation is SpecializationImplementation.Generated adjGen) { addAdjoint = adjGen.Item.IsInvert; isSelfAdjoint = adjGen.Item.IsSelfInverse; } if (ctl != null && ctl.Implementation is SpecializationImplementation.Generated ctlGen) { addControlled = ctlGen.Item.IsDistribute; } if (ctlAdj != null && ctlAdj.Implementation is SpecializationImplementation.Generated ctlAdjGen) { addAdjoint = addAdjoint || (ctlAdjGen.Item.IsInvert && ctl.Implementation.IsGenerated); addControlled = addControlled || (ctlAdjGen.Item.IsDistribute && adj.Implementation.IsGenerated); isSelfAdjoint = isSelfAdjoint || ctlAdjGen.Item.IsSelfInverse; } } else if (ctlAdj != null && ctlAdj.Implementation is SpecializationImplementation.Generated gen) { addControlled = this.InAdjoint && gen.Item.IsDistribute; addAdjoint = this.InControlled && gen.Item.IsInvert; isSelfAdjoint = gen.Item.IsSelfInverse; } var props = new List <OpProperty>(); if (addAdjoint) { props.Add(OpProperty.Adjointable); } if (addControlled) { props.Add(OpProperty.Controllable); } var newSig = new ResolvedSignature( this.CurrentCallable.Callable.Signature.TypeParameters, paramsType, ResolvedType.New(ResolvedTypeKind.UnitType), new CallableInformation(ResolvedCharacteristics.FromProperties(props), new InferredCallableInformation(isSelfAdjoint, false))); var controlledSig = new ResolvedSignature( newSig.TypeParameters, ResolvedType.New(ResolvedTypeKind.NewTupleType(ImmutableArray.Create( ResolvedType.New(ResolvedTypeKind.NewArrayType(ResolvedType.New(ResolvedTypeKind.Qubit))), newSig.ArgumentType))), newSig.ReturnType, newSig.Information); var specializations = new List <QsSpecialization>() { MakeSpec(QsSpecializationKind.QsBody, newSig, bodyImplementation) }; if (addAdjoint) { specializations.Add(MakeSpec( QsSpecializationKind.QsAdjoint, newSig, SpecializationImplementation.NewGenerated(QsGeneratorDirective.Invert))); } if (addControlled) { specializations.Add(MakeSpec( QsSpecializationKind.QsControlled, controlledSig, SpecializationImplementation.NewGenerated(QsGeneratorDirective.Distribute))); } if (addAdjoint && addControlled) { specializations.Add(MakeSpec( QsSpecializationKind.QsControlledAdjoint, controlledSig, SpecializationImplementation.NewGenerated(QsGeneratorDirective.Distribute))); } return(newSig, specializations); }
public void ParseOp() { ArgDeclType BuildArgument(string name, ResolvedType t) { var validName = QsLocalSymbol.NewValidName(NonNullable <string> .New(name)); var info = new InferredExpressionInformation(false, false); return(new ArgDeclType(validName, t, info, QsNullable <Tuple <int, int> > .Null, EmptyRange)); } string[] comments = { "# Summary", "Convenience function that performs state preparation by applying a ", "`statePrepUnitary` on the input state, followed by adiabatic state ", "preparation using a `adiabaticUnitary`, and finally phase estimation ", "with respect to `qpeUnitary`on the resulting state using a ", "`phaseEstAlgorithm`.", "", "# Input", "## statePrepUnitary", "An oracle representing state preparation for the initial dynamical", "generator.", "## adiabaticUnitary", "An oracle representing the adiabatic evolution algorithm to be used", "to implement the sweeps to the final state of the algorithm.", "## qpeUnitary", "An oracle representing a unitary operator $U$ representing evolution", "for time $\\delta t$ under a dynamical generator with ground state", "$\\ket{\\phi}$ and ground state energy $E = \\phi\\\\,\\delta t$.", "## phaseEstAlgorithm", "An operation that performs phase estimation on a given unitary operation.", "See [iterative phase estimation](/quantum/libraries/characterization#iterative-phase-estimation)", "for more details.", "## qubits", "A register of qubits to be used to perform the simulation.", "", "# Output", "An estimate $\\hat{\\phi}$ of the ground state energy $\\phi$", "of the generator represented by $U$." }; string expected = @"### YamlMime:QSharpType uid: microsoft.quantum.canon.adiabaticstateenergyunitary name: AdiabaticStateEnergyUnitary type: operation namespace: Microsoft.Quantum.Canon summary: |- Convenience function that performs state preparation by applying a `statePrepUnitary` on the input state, followed by adiabatic state preparation using a `adiabaticUnitary`, and finally phase estimation with respect to `qpeUnitary`on the resulting state using a `phaseEstAlgorithm`. syntax: 'operation AdiabaticStateEnergyUnitary (statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit is Adj + Ctl), phaseEstAlgorithm : ((Microsoft.Quantum.Canon.DiscreteOracle, Qubit[]) => Double), qubits : Qubit[]) : Double' input: content: '(statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit is Adj + Ctl), phaseEstAlgorithm : ((Microsoft.Quantum.Canon.DiscreteOracle, Qubit[]) => Double), qubits : Qubit[])' types: - name: statePrepUnitary summary: |- An oracle representing state preparation for the initial dynamical generator. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit - name: adiabaticUnitary summary: |- An oracle representing the adiabatic evolution algorithm to be used to implement the sweeps to the final state of the algorithm. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit - name: qpeUnitary summary: |- An oracle representing a unitary operator $U$ representing evolution for time $\delta t$ under a dynamical generator with ground state $\ket{\phi}$ and ground state energy $E = \phi\\,\delta t$. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit functors: - Adjoint - Controlled - name: phaseEstAlgorithm summary: |- An operation that performs phase estimation on a given unitary operation. See [iterative phase estimation](/quantum/libraries/characterization#iterative-phase-estimation) for more details. isOperation: true input: types: - uid: microsoft.quantum.canon.discreteoracle - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Double - name: qubits summary: A register of qubits to be used to perform the simulation. isArray: true isPrimitive: true uid: Qubit output: content: Double types: - summary: |- An estimate $\hat{\phi}$ of the ground state energy $\phi$ of the generator represented by $U$. isPrimitive: true uid: Double ... "; var qubitArrayType = ResolvedType.New(QsType.NewArrayType(ResolvedType.New(QsType.Qubit))); var unitType = ResolvedType.New(QsType.UnitType); var doubleType = ResolvedType.New(QsType.Double); var oracleType = ResolvedType.New(QsType.NewUserDefinedType(new UserDefinedType(CanonName, NonNullable <string> .New("DiscreteOracle"), QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null))); var noInfo = CallableInformation.NoInformation; var acFunctors = ResolvedCharacteristics.FromProperties(new[] { OpProperty.Adjointable, OpProperty.Controllable }); var acInfo = new CallableInformation(acFunctors, InferredCallableInformation.NoInformation); var qubitToUnitOp = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(qubitArrayType, unitType), noInfo)); var qubitToUnitOpAC = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(qubitArrayType, unitType), acInfo)); var phaseEstArgs = new ResolvedType[] { oracleType, qubitArrayType }.ToImmutableArray(); var phaseEstArgTuple = ResolvedType.New(QsType.NewTupleType(phaseEstArgs)); var phaseEstOp = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(phaseEstArgTuple, doubleType), noInfo)); var typeParams = new QsLocalSymbol[] { }.ToImmutableArray(); var argTypes = new ResolvedType[] { qubitToUnitOp, qubitToUnitOp, qubitToUnitOpAC, phaseEstOp, qubitArrayType }.ToImmutableArray(); var argTupleType = ResolvedType.New(QsType.NewTupleType(argTypes)); var signature = new ResolvedSignature(typeParams, argTupleType, doubleType, noInfo); var args = new List <ArgDeclType> { BuildArgument("statePrepUnitary", qubitToUnitOp), BuildArgument("adiabaticUnitary", qubitToUnitOp), BuildArgument("qpeUnitary", qubitToUnitOpAC), BuildArgument("phaseEstAlgorithm", phaseEstOp), BuildArgument("qubits", qubitArrayType) } .ConvertAll(arg => QsTuple <ArgDeclType> .NewQsTupleItem(arg)) .ToImmutableArray(); var argTuple = QsTuple <ArgDeclType> .NewQsTuple(args); var specs = new QsSpecialization[] { }.ToImmutableArray(); var qsCallable = new QsCallable(QsCallableKind.Operation, MakeFullName("AdiabaticStateEnergyUnitary"), ImmutableArray <QsDeclarationAttribute> .Empty, NonNullable <string> .New("Techniques.qs"), ZeroLocation, signature, argTuple, specs, comments.ToImmutableArray(), QsComments.Empty); var callable = new DocCallable("Microsoft.Quantum.Canon", qsCallable); var stream = new StringWriter(); callable.WriteToFile(stream); var s = stream.ToString(); Assert.Equal(expected, s); }
/// <summary> /// Creates a separate callable for each intrinsic specialization, /// and replaces the specialization implementations of the original callable with a call to these. /// Self adjoint generation directives in intrinsic callables are replaced by a provided implementation. /// Type constructors and generic callables or callables that already define a target instruction name are left unchanged. /// </summary> /// <exception cref="ArgumentException"> /// An intrinsic callable contains non-intrinsic specializations /// or a non-intrinsic callable contains intrinsic specializations, /// or the a callable doesn't have a body specialization. /// </exception> /// <exception cref="InvalidOperationException"> /// A specialization has explicit type arguments; /// Monomorphization needs to run before separating target instructions. /// </exception> private static QsNamespace LiftIntrinsicSpecializations(QsNamespace ns) { var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>(); foreach (var element in ns.Elements) { if (element is QsNamespaceElement.QsCallable c && c.Item.Signature.TypeParameters.Length == 0 && !c.Item.Kind.IsTypeConstructor) { if (c.Item.IsIntrinsic) { QsCallable callable = c.Item; if (!callable.Specializations.Any(spec => spec.Kind.IsQsBody)) { throw new ArgumentException("missing body specialization"); } else if (callable.Specializations.Any(spec => spec.TypeArguments.IsValue)) { throw new InvalidOperationException("specialization with type arguments"); } else if (callable.Specializations.Length == 1 && callable.Attributes.Any(BuiltIn.DefinesTargetInstruction)) { elements.Add(element); } else { QsQualifiedName GeneratedName(QsSpecializationKind kind) => new QsQualifiedName(callable.FullName.Namespace, $"{callable.FullName.Name}{SpecializationSuffix(kind)}"); var specializations = ImmutableArray.CreateRange(callable.Specializations.Select(spec => { var inferredInfo = spec.Signature.Information.InferredInformation; if (!inferredInfo.IsIntrinsic && !inferredInfo.IsSelfAdjoint) { throw new ArgumentException("non-intrinsic specialization for intrinsic callable"); } // Get the correct argument tuple both for the added intrinsic callable // and the generated provided specialization that replaces the intrinsic one. var argTuple = BuildSpecArgTuple(callable.ArgumentTuple, spec.Kind); // Create a separate callable for that specialization, // unless the specialization is not needed for a self-adjoint callable. var genCallableSignature = new ResolvedSignature( ImmutableArray <QsLocalSymbol> .Empty, spec.Signature.ArgumentType, spec.Signature.ReturnType, new CallableInformation( ResolvedCharacteristics.Empty, new InferredCallableInformation(isIntrinsic: true, isSelfAdjoint: false))); var genCallableName = GeneratedName( inferredInfo.IsSelfAdjoint && spec.Kind.IsQsAdjoint ? QsSpecializationKind.QsBody : inferredInfo.IsSelfAdjoint && spec.Kind.IsQsControlledAdjoint ? QsSpecializationKind.QsControlled : spec.Kind); if (!inferredInfo.IsSelfAdjoint || spec.Kind.IsQsBody || spec.Kind.IsQsControlled) { var genCallableBody = new QsSpecialization( QsSpecializationKind.QsBody, genCallableName, spec.Attributes, spec.Source, QsNullable <QsLocation> .Null, spec.TypeArguments, genCallableSignature, SpecializationImplementation.Intrinsic, spec.Documentation, spec.Comments); var genCallable = new QsCallable( callable.Kind, genCallableName, callable.Attributes, callable.Access, spec.Source, spec.Location, genCallableSignature, argTuple, ImmutableArray.Create(genCallableBody), ImmutableArray <string> .Empty, QsComments.Empty); elements.Add(QsNamespaceElement.NewQsCallable(genCallable)); } // Create a specialization that calls into the generated callable, // or the corresponding callable no callable for the specialization // has been added due to hte operation being self-adjoint. var genCallableType = callable.Kind == QsCallableKind.Operation ? OperationTypeFromSignature(genCallableSignature) : TypeKind.NewFunction(genCallableSignature.ArgumentType, genCallableSignature.ReturnType); var call = SyntaxGenerator.CallNonGeneric( IdentifierForCallable(genCallableName, genCallableType), SyntaxGenerator.ArgumentTupleAsExpression(argTuple)); var statement = new QsStatement( QsStatementKind.NewQsReturnStatement(call), LocalDeclarations.Empty, QsNullable <QsLocation> .Null, QsComments.Empty); var localDeclarations = new LocalDeclarations( SyntaxGenerator.ValidDeclarations(SyntaxGenerator.ExtractItems(argTuple))); return(spec.WithImplementation(SpecializationImplementation.NewProvided( argTuple, new QsScope(ImmutableArray.Create(statement), localDeclarations)))); })); // Create a callable that contains all specializations that // call into the generated callables for each specialization. var inlineAttribute = AttributeUtils.BuildAttribute(BuiltIn.Inline.FullName, SyntaxGenerator.UnitValue); var signature = new ResolvedSignature( ImmutableArray <QsLocalSymbol> .Empty, callable.Signature.ArgumentType, callable.Signature.ReturnType, new CallableInformation( callable.Signature.Information.Characteristics, new InferredCallableInformation(isSelfAdjoint: callable.IsSelfAdjoint, isIntrinsic: false))); var redirect = new QsCallable( callable.Kind, callable.FullName, ImmutableArray.Create(inlineAttribute), callable.Access, callable.Source, callable.Location, signature, callable.ArgumentTuple, specializations, callable.Documentation, callable.Comments); elements.Add(QsNamespaceElement.NewQsCallable(redirect)); } } else if (c.Item.Specializations.Any(spec => spec.Implementation.IsIntrinsic)) { throw new ArgumentException("intrinsic specialization for non-intrinsic callable"); } else { elements.Add(element); } }
private static TypeKind OperationTypeFromSignature(ResolvedSignature signature) => TypeKind.NewOperation( Tuple.Create(signature.ArgumentType, signature.ReturnType), signature.Information);
public void ExcludeInaccessible() { var elements = new[] { AccessModifier.DefaultAccess, AccessModifier.Internal } .SelectMany(access => { var source = NonNullable <string> .New("Tests.qs"); var unit = ResolvedType.New(QsType.UnitType); var signature = new ResolvedSignature(Array.Empty <QsLocalSymbol>().ToImmutableArray(), unit, unit, CallableInformation.NoInformation); var argumentTuple = QsTuple <ArgDeclType> .NewQsTuple(ImmutableArray.Create <QsTuple <ArgDeclType> >()); var callable = new QsCallable(kind: QsCallableKind.Operation, fullName: MakeFullName(access + "Operation"), attributes: ImmutableArray <QsDeclarationAttribute> .Empty, modifiers: new Modifiers(access), sourceFile: source, location: ZeroLocation, signature: signature, argumentTuple: argumentTuple, specializations: ImmutableArray.Create <QsSpecialization>(), documentation: ImmutableArray.Create <string>(), comments: QsComments.Empty); var typeItems = QsTuple <QsTypeItem> .NewQsTuple( ImmutableArray.Create(QsTuple <QsTypeItem> .NewQsTupleItem(QsTypeItem.NewAnonymous(unit)))); var type = new QsCustomType(fullName: MakeFullName(access + "Type"), attributes: ImmutableArray <QsDeclarationAttribute> .Empty, modifiers: new Modifiers(access), sourceFile: source, location: ZeroLocation, type: unit, typeItems: typeItems, documentation: ImmutableArray.Create <string>(), comments: QsComments.Empty); return(new[] { QsNamespaceElement.NewQsCallable(callable), QsNamespaceElement.NewQsCustomType(type) }); }); var emptyLookup = Array.Empty <ImmutableArray <string> >().ToLookup(x => NonNullable <string> .New("")); var ns = new QsNamespace(CanonName, elements.ToImmutableArray(), emptyLookup); var docNs = new DocNamespace(ns); var stream = new MemoryStream(); docNs.WriteToStream(stream, null); var expected = @"### YamlMime:QSharpNamespace uid: microsoft.quantum.canon name: Microsoft.Quantum.Canon operations: - uid: microsoft.quantum.canon.defaultaccessoperation summary: '' newtypes: - uid: microsoft.quantum.canon.defaultaccesstype summary: '' ... "; var actual = Encoding.UTF8.GetString(stream.ToArray()); Assert.Equal(expected, actual); }