Ejemplo n.º 1
0
 /// <summary>
 /// Given the argument tuple of a specialization, returns the argument tuple for its controlled version.
 /// Returns null if the given argument tuple is null.
 /// </summary>
 private static QsTuple <LocalVariableDeclaration <QsLocalSymbol> > ControlledArg(QsTuple <LocalVariableDeclaration <QsLocalSymbol> > arg) =>
 arg != null
     ? SyntaxGenerator.WithControlQubits(arg,
                                         QsNullable <Tuple <int, int> > .Null,
                                         QsLocalSymbol.NewValidName(NonNullable <string> .New(InternalUse.ControlQubitsName)),
                                         QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null)
     : null;
Ejemplo n.º 2
0
            static 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));
            }
Ejemplo n.º 3
0
            static ArgDeclType BuildArgument(string name, ResolvedType t)
            {
                var validName = QsLocalSymbol.NewValidName(name);
                var info      = new InferredExpressionInformation(false, false);

                return(new ArgDeclType(validName, t, info, QsNullable <Position> .Null, Range.Zero));
            }
Ejemplo n.º 4
0
 /// <summary>
 /// Given the argument tuple of a specialization, returns the argument tuple for its controlled version.
 /// Returns null if the given argument tuple is null.
 /// </summary>
 private static QsTuple <LocalVariableDeclaration <QsLocalSymbol> >?ControlledArg(QsTuple <LocalVariableDeclaration <QsLocalSymbol> > arg) =>
 arg != null
     ? SyntaxGenerator.WithControlQubits(
     arg,
     QsNullable <Position> .Null,
     QsLocalSymbol.NewValidName(InternalUse.ControlQubitsName),
     QsNullable <Range> .Null)
     : null;
        // private methods

        private static ArgumentTuple BuildSpecArgTuple(ArgumentTuple callableArg, QsSpecializationKind specKind) =>
        specKind.IsQsControlled || specKind.IsQsControlledAdjoint
                ? SyntaxGenerator.WithControlQubits(
            callableArg,
            QsNullable <Position> .Null,
            QsLocalSymbol.NewValidName(InternalUse.ControlQubitsName),
            QsNullable <DataTypes.Range> .Null)
                : callableArg;
            private (QsCallable, ResolvedType) GenerateOperation(CallableDetails callable, QsScope contents)
            {
                var newName = UniqueVariableNames.PrependGuid(callable.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(callable, newName, paramTypes, SpecializationImplementation.NewProvided(parameters, contents));

                var generatedCallable = new QsCallable(
                    QsCallableKind.Operation,
                    newName,
                    ImmutableArray<QsDeclarationAttribute>.Empty,
                    new Modifiers(AccessModifier.Internal),
                    callable.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, callable.Callable.FullName, newName);

                return (generatedCallable, signature.ArgumentType);
            }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Returns the signature help information for a call expression if there is such an expression at the specified position.
        /// Returns null if some parameters are unspecified (null),
        /// or if the specified position is not a valid position within the currently processed file content,
        /// or if no call expression exists at the specified position at this time,
        /// or if no signature help information can be provided for the call expression at the specified position.
        /// </summary>
        public static SignatureHelp?SignatureHelp(
            this FileContentManager file,
            CompilationUnit compilation,
            Position?position,
            MarkupKind format = MarkupKind.PlainText)
        {
            // getting the relevant token (if any)

            var fragment = file?.TryGetFragmentAt(position, out var _, includeEnd: true);

            if (file is null || position is null || fragment?.Kind == null || compilation == null)
            {
                return(null);
            }
            var fragmentStart = fragment.Range.Start;

            // getting the overlapping call expressions (if any), and determine the header of the called callable

            bool OverlapsWithPosition(Range symRange) => (fragmentStart + symRange).ContainsEnd(position);

            var overlappingEx = fragment.Kind.CallExpressions().Where(ex => ex.Range.IsValue && OverlapsWithPosition(ex.Range.Item)).ToList();

            if (!overlappingEx.Any())
            {
                return(null);
            }
            overlappingEx.Sort((ex1, ex2) => // for nested call expressions, the last expressions (by range) is always the closest one
            {
                var(x, y)  = (ex1.Range.Item, ex2.Range.Item);
                int result = x.Start.CompareTo(y.Start);
                return(result == 0 ? x.End.CompareTo(y.End) : result);
            });

            var nsName = file.TryGetNamespaceAt(position);

            var(method, args) = overlappingEx.Last().Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .CallLikeExpression c ? (c.Item1, c.Item2) : (null, null);
            if (nsName == null || method == null || args == null)
            {
                return(null);
            }

            // getting the called identifier as well as what functors have been applied to it

            List <QsFunctor> FunctorApplications(ref QsExpression ex)
            {
                var(next, inner) =
                    ex.Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .AdjointApplication adj ? (QsFunctor.Adjoint, adj.Item) :
                    ex.Expression is QsExpressionKind <QsExpression, QsSymbol, QsType> .ControlledApplication ctl ? (QsFunctor.Controlled, ctl.Item) :
                    (null, null);
                var fs = inner == null ? new List <QsFunctor>() : FunctorApplications(ref inner);

                if (next != null)
                {
                    fs.Add(next);
                }
                ex = inner ?? ex;
                return(fs);
            }

            var functors = FunctorApplications(ref method);
            var id       = method.Expression as QsExpressionKind <QsExpression, QsSymbol, QsType> .Identifier;

            if (id == null)
            {
                return(null);
            }

            // extracting and adapting the relevant information for the called callable

            ResolutionResult <CallableDeclarationHeader> .Found?methodDecl = null;
            if (id.Item1.Symbol is QsSymbolKind <QsSymbol> .Symbol sym)
            {
                methodDecl =
                    compilation.GlobalSymbols.TryResolveAndGetCallable(
                        sym.Item,
                        nsName,
                        file.FileName)
                    as ResolutionResult <CallableDeclarationHeader> .Found;
            }
            else if (id.Item1.Symbol is QsSymbolKind <QsSymbol> .QualifiedSymbol qualSym)
            {
                methodDecl =
                    compilation.GlobalSymbols.TryGetCallable(
                        new QsQualifiedName(qualSym.Item1, qualSym.Item2),
                        nsName,
                        file.FileName)
                    as ResolutionResult <CallableDeclarationHeader> .Found;
            }

            if (methodDecl == null)
            {
                return(null);
            }

            var(documentation, argTuple) = (methodDecl.Item.Documentation, methodDecl.Item.ArgumentTuple);
            var nrCtlApplications = functors.Where(f => f.Equals(QsFunctor.Controlled)).Count();

            while (nrCtlApplications-- > 0)
            {
                var ctlQsName = QsLocalSymbol.NewValidName(nrCtlApplications == 0 ? "cs" : $"cs{nrCtlApplications}");
                argTuple = SyntaxGenerator.WithControlQubits(argTuple, QsNullable <Position> .Null, ctlQsName, QsNullable <Range> .Null);
            }

            // now that we now what callable is called we need to check which argument should come next

            bool BeforePosition(Range symRange) => fragmentStart + symRange.End < position;

            IEnumerable <(Range?, string?)> ExtractParameterRanges(
                QsExpression?ex, QsTuple <LocalVariableDeclaration <QsLocalSymbol> > decl)
            {
                var @null = ((Range?)null, (string?)null);

                IEnumerable <(Range?, string?)> SingleItem(string paramName)
                {
                    var arg = ex?.Range == null ? ((Range?)null, paramName)
                        : ex.Range.IsValue ? (ex.Range.Item, paramName)
                        : @null; // no signature help if there are invalid expressions

                    return(new[] { arg });
                }

                if (decl is QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .QsTupleItem dItem)
                {
                    return(SingleItem(dItem.Item.VariableName is QsLocalSymbol.ValidName n ? n.Item : "__argName__"));
                }

                var declItems = decl as QsTuple <LocalVariableDeclaration <QsLocalSymbol> > .QsTuple;
                var exItems   = ex?.Expression as QsExpressionKind <QsExpression, QsSymbol, QsType> .ValueTuple;

                if (declItems == null)
                {
                    return(new[] { @null });
                }
                if (exItems == null && declItems.Item.Length > 1)
                {
                    return(SingleItem(decl.PrintArgumentTuple()));
                }

                var argItems = exItems != null
                    ? exItems.Item.ToImmutableArray <QsExpression?>()
                    : ex == null
                    ? ImmutableArray <QsExpression?> .Empty
                    : ImmutableArray.Create <QsExpression?>(ex);

                return(argItems.AddRange(Enumerable.Repeat <QsExpression?>(null, declItems.Item.Length - argItems.Length))
                       .Zip(declItems.Item, (e, d) => (e, d))
                       .SelectMany(arg => ExtractParameterRanges(arg.Item1, arg.Item2)));
            }

            var callArgs = ExtractParameterRanges(args, argTuple).ToArray();

            if (id == null || callArgs == null || callArgs.Any(item => item.Item2 == null))
            {
                return(null); // no signature help if there are invalid expressions
            }

            // finally we can build the signature help information

            MarkupContent AsMarkupContent(string str) => new MarkupContent
            {
                Kind = format, Value = str
            };
            ParameterInformation AsParameterInfo(string?paramName) => new ParameterInformation
            {
                Label         = paramName,
                Documentation = AsMarkupContent(documentation.ParameterDescription(paramName))
            };

            var signatureLabel = $"{methodDecl.Item.QualifiedName.Name} {argTuple.PrintArgumentTuple()}";

            foreach (var f in functors)
            {
                if (f.IsAdjoint)
                {
                    signatureLabel = $"{Keywords.qsAdjointFunctor.id} {signatureLabel}";
                }
                if (f.IsControlled)
                {
                    signatureLabel = $"{Keywords.qsControlledFunctor.id} {signatureLabel}";
                }
            }

            var doc  = documentation.PrintSummary(format == MarkupKind.Markdown).Trim();
            var info = new SignatureInformation
            {
                Documentation = AsMarkupContent(doc),
                Label         = signatureLabel, // Note: the label needs to be expressed in a way that the active parameter is detectable
                Parameters    = callArgs.Select(d => d.Item2).Select(AsParameterInfo).ToArray()
            };
            var precedingArgs = callArgs
                                .TakeWhile(item => item.Item1 == null || BeforePosition(item.Item1)) // skip args that have already been typed or - in the case of inner items - are missing
                                .Reverse().SkipWhile(item => item.Item1 == null);                    // don't count missing, i.e. not yet typed items, of the relevant inner argument tuple

            return(new SignatureHelp
            {
                Signatures = new[] { info }, // since we don't support overloading there is just one signature here
                ActiveSignature = 0,
                ActiveParameter = precedingArgs.Count()
            });
        }