Пример #1
0
 /// <summary>
 /// Return the argument tuple as well as the QsScope if the implementation is provided.
 /// Returns null if the given implementation is null or not provided.
 /// </summary>
 private static (QsTuple <LocalVariableDeclaration <QsLocalSymbol> >, QsScope)? GetContent(this SpecializationImplementation impl) =>
Пример #2
0
            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);
            }
        /// <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);
                    }
                }
Пример #4
0
            private (QsCallable, ResolvedType) GenerateOperation(QsScope contents)
            {
                var newName = UniqueVariableNames.PrependGuid(this.CurrentCallable.Callable.FullName);

                var knownVariables = contents.KnownSymbols.Variables;

                var parameters = QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .NewQsTuple(knownVariables
                                                                                                 .Select(var => QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .NewQsTupleItem(new LocalVariableDeclaration <QsLocalSymbol>(
                                                                                                                                                                                        QsLocalSymbol.NewValidName(var.VariableName),
                                                                                                                                                                                        var.Type,
                                                                                                                                                                                        new InferredExpressionInformation(false, false),
                                                                                                                                                                                        var.Position,
                                                                                                                                                                                        var.Range)))
                                                                                                 .ToImmutableArray());

                var paramTypes = ResolvedType.New(ResolvedTypeKind.UnitType);

                if (knownVariables.Length == 1)
                {
                    paramTypes = knownVariables.First().Type;
                }
                else if (knownVariables.Length > 1)
                {
                    paramTypes = ResolvedType.New(ResolvedTypeKind.NewTupleType(knownVariables
                                                                                .Select(var => var.Type)
                                                                                .ToImmutableArray()));
                }

                var(signature, specializations) = this.MakeSpecializations(newName, paramTypes, SpecializationImplementation.NewProvided(parameters, contents));

                var generatedCallable = new QsCallable(
                    QsCallableKind.Operation,
                    newName,
                    ImmutableArray <QsDeclarationAttribute> .Empty,
                    new Modifiers(AccessModifier.Internal),
                    this.CurrentCallable.Callable.SourceFile,
                    QsNullable <QsLocation> .Null,
                    signature,
                    parameters,
                    specializations.ToImmutableArray(),
                    ImmutableArray <string> .Empty,
                    QsComments.Empty);

                // Change the origin of all type parameter references to use the new name and make all variables immutable
                generatedCallable = UpdateGeneratedOp.Apply(generatedCallable, knownVariables, this.CurrentCallable.Callable.FullName, newName);

                return(generatedCallable, signature.ArgumentType);
            }
        /// <summary>
        /// Replaces self adjoint generation directives in non-intrinsic callables with a provided implementation
        /// that calls the appropriate specialization of the callable.
        /// Intrinsic callables are left unchanged.
        /// </summary>
        private static QsNamespace ReplaceSelfAdjointSpecializations(QsNamespace ns)
        {
            var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>();

            foreach (var element in ns.Elements)
            {
                if (element is QsNamespaceElement.QsCallable c)
                {
                    if (c.Item.IsSelfAdjoint && !c.Item.IsIntrinsic)
                    {
                        var callableId = IdentifierForCallable(
                            c.Item.FullName,
                            OperationTypeFromSignature(c.Item.Signature));

                        var callable = c.Item.WithSpecializations(specs =>
                                                                  ImmutableArray.CreateRange(specs.Select(spec =>
                        {
                            if (spec.Kind.IsQsBody || spec.Kind.IsQsControlled)
                            {
                                return(spec);
                            }
                            else
                            {
                                var argTuple = BuildSpecArgTuple(c.Item.ArgumentTuple, spec.Kind);
                                var callee   = spec.Kind.IsQsControlledAdjoint
                                        ? SyntaxGenerator.AutoGeneratedExpression(
                                    ExpressionKind.NewControlledApplication(callableId),
                                    OperationTypeFromSignature(spec.Signature),
                                    false)
                                        : callableId;

                                var call = SyntaxGenerator.CallNonGeneric(
                                    callee,
                                    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))));
                            }
                        })));
                        elements.Add(QsNamespaceElement.NewQsCallable(callable));
                    }
                    else
                    {
                        elements.Add(element);
                    }
                }
                else
                {
                    elements.Add(element);
                }
            }
            return(new QsNamespace(ns.Name, elements.ToImmutable(), ns.Documentation));
        }