Skip to content
This repository has been archived by the owner on Jan 12, 2024. It is now read-only.

Commit

Permalink
Support for Conjugations as Statements - Part II (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
bettinaheim authored Aug 16, 2019
1 parent 8bb44a5 commit 6fbd0c5
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/QsCompiler/CompilationManager/DataStructures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,10 @@ internal struct FragmentTree
internal struct TreeNode
{
private readonly Position relPosition;
private readonly Position rootPosition;
public readonly CodeFragment Fragment;
public readonly IReadOnlyList<TreeNode> Children;
public Position GetRootPosition() => rootPosition.Copy();
public Position GetPositionRelativeToRoot() => relPosition.Copy();

/// <summary>
Expand All @@ -339,6 +341,7 @@ public TreeNode(CodeFragment fragment, IReadOnlyList<TreeNode> children, Positio
var fragStart = fragment.GetRange().Start;
if (!Utils.IsValidPosition(parentStart)) throw new ArgumentException(nameof(parentStart));
if (fragStart.IsSmallerThan(parentStart)) throw new ArgumentException(nameof(parentStart), "parentStart needs to be smaller than or equal to the fragment start");
this.rootPosition = parentStart;
this.relPosition = fragStart.Subtract(parentStart);
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/QsCompiler/CompilationManager/TypeChecking.cs
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,10 @@ QsNullable<QsLocation> RelativeLocation(FragmentTree.TreeNode node) =>
{
var innerTransformation = BuildScope(nodes.Current.Children, symbolTracker, diagnostics);
var inner = new QsPositionedBlock(innerTransformation, RelativeLocation(nodes.Current), nodes.Current.Fragment.Comments);
var built = Statements.NewConjugation(outer, inner);
diagnostics.AddRange(built.Item2.Select(msg => Diagnostics.Generate(symbolTracker.SourceFile.Value, msg.Item2, nodes.Current.GetRootPosition())));

statement = Statements.NewConjugation(outer, inner);
statement = built.Item1;
proceed = nodes.MoveNext();
return true;
}
Expand Down
6 changes: 3 additions & 3 deletions src/QsCompiler/Core/ExpressionTransformation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,15 @@ and ExpressionTransformation(?enableKindTransformations) =
abstract member Type : ExpressionTypeTransformation
default this.Type = typeTransformation

abstract member onRange : QsNullable<QsPositionInfo*QsPositionInfo> -> QsNullable<QsPositionInfo*QsPositionInfo>
default this.onRange r = r
abstract member onRangeInformation : QsNullable<QsPositionInfo*QsPositionInfo> -> QsNullable<QsPositionInfo*QsPositionInfo>
default this.onRangeInformation r = r

abstract member onExpressionInformation : InferredExpressionInformation -> InferredExpressionInformation
default this.onExpressionInformation info = info

abstract member Transform : TypedExpression -> TypedExpression
default this.Transform (ex : TypedExpression) =
let range = this.onRange ex.Range
let range = this.onRangeInformation ex.Range
let kind = this.Kind.Transform ex.Expression
let typeParamResolutions = ex.TypeParameterResolutions
let exType = this.Type.Transform ex.ResolvedType
Expand Down
2 changes: 1 addition & 1 deletion src/QsCompiler/Core/SyntaxGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type private StripRangeInfoFromType () =
type private StripRangeInfoFromExpression () =
inherit ExpressionTransformation()
let typeTransformation = new StripRangeInfoFromType() :> ExpressionTypeTransformation
override this.onRange _ = QsRangeInfo.Null
override this.onRangeInformation _ = QsRangeInfo.Null
override this.Type = typeTransformation

type private StripRangeInfoFromScope() =
Expand Down
4 changes: 3 additions & 1 deletion src/QsCompiler/DataStructures/Diagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ type ErrorCode =
| ValueUpdateWithinAutoInversion = 6314
| RUSloopWithinAutoInversion = 6315
| QuantumDependencyOutsideExprStatement = 6316
| InvalidReassignmentInApplyBlock = 6317

| UnexpectedCommandLineCompilerException = 7001
| MissingInputFileOrSnippet = 7002
Expand Down Expand Up @@ -551,7 +552,8 @@ type DiagnosticItem =
| ErrorCode.ValueUpdateWithinAutoInversion -> "Auto-generation of inversions is not supported for operations that contain set-statements."
| ErrorCode.RUSloopWithinAutoInversion -> "Auto-generation of inversions is not supported for operations that contain repeat-until-success-loops."
| ErrorCode.QuantumDependencyOutsideExprStatement -> "Auto-generation of inversions is not supported for operations that contain operation calls outside expression statements."

| ErrorCode.InvalidReassignmentInApplyBlock -> "Variables that are used in the within-block (specifying the outer transformation) cannot be reassigned in the apply-block (specifying the inner transformation)."

| ErrorCode.UnexpectedCommandLineCompilerException -> "The command line compiler threw an exception."
| ErrorCode.MissingInputFileOrSnippet -> "The command line compiler needs a list of files or a code snippet to process."
| ErrorCode.SnippetAndInputArguments -> "The command line compiler can accept a list of files or a code snippet, but not both."
Expand Down
19 changes: 16 additions & 3 deletions src/QsCompiler/SyntaxProcessor/StatementVerification.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Microsoft.Quantum.QsCompiler.SyntaxProcessing.Statements
open System
open System.Collections.Generic
open System.Collections.Immutable
open System.Linq
open Microsoft.Quantum.QsCompiler
open Microsoft.Quantum.QsCompiler.DataTypes
open Microsoft.Quantum.QsCompiler.Diagnostics
Expand All @@ -15,6 +16,7 @@ open Microsoft.Quantum.QsCompiler.SyntaxProcessing.VerificationTools
open Microsoft.Quantum.QsCompiler.SyntaxTokens
open Microsoft.Quantum.QsCompiler.SymbolTracker
open Microsoft.Quantum.QsCompiler.SyntaxTree
open Microsoft.Quantum.QsCompiler.Transformations.SearchAndReplace


// some utils for type checking statements
Expand Down Expand Up @@ -255,14 +257,25 @@ let NewRepeatStatement (symbols : SymbolTracker<_>) (repeatBlock : QsPositionedB

/// Given a positioned block of Q# statements specifying the transformation to conjugate (inner transformation V),
/// as well as a positioned block of Q# statements specifying the transformation to conjugate it with (outer transformation U),
/// builds and returns the corresponding conjugation statement representing the patter U*VU where the order of application is right to left and U* is the adjoint of U.
/// builds and returns the corresponding conjugation statement representing the patter U*VU where the order of application is right to left and U* is the adjoint of U.
/// Returns an array with diagnostics and the corresponding statement offset for all invalid variable reassignments in the apply-block.
/// Throws an ArgumentException if the given block specifying the outer transformation contains no location information.
let NewConjugation (outer : QsPositionedBlock, inner : QsPositionedBlock) =
let location = outer.Location |> function
| Null -> ArgumentException "no location is set for the given within-block defining the conjugating transformation" |> raise
| Value loc -> loc
// TODO: WE NEED TO GIVE PROPER ERRORS IF A VARIABLE THAT IS USED IN THE OUTER BLOCK IS REASSIGNED IN THE INNER BLOCK
QsConjugation.New (outer, inner) |> QsConjugation |> asStatement QsComments.Empty location []
let usedInOuter =
let accumulate = new AccumulateIdentifiers()
accumulate.Transform outer.Body |> ignore
accumulate.UsedLocalVariables
let updatedInInner =
let accumulate = new AccumulateIdentifiers()
accumulate.Transform inner.Body |> ignore
accumulate.ReassignedVariables
let updateErrs =
updatedInInner |> Seq.filter (fun updated -> usedInOuter.Contains updated.Key) |> Seq.collect id
|> Seq.map (fun loc -> (loc.Offset, loc.Range |> QsCompilerDiagnostic.Error (ErrorCode.InvalidReassignmentInApplyBlock, []))) |> Seq.toArray
QsConjugation.New (outer, inner) |> QsConjugation |> asStatement QsComments.Empty location [], updateErrs

/// Given the location of the statement header as well as a symbol tracker containing all currently declared symbols,
/// builds the Q# using- or borrowing-statement (depending on the given kind) at the given location
Expand Down
19 changes: 19 additions & 0 deletions src/QsCompiler/Tests.Compiler/LocalVerificationTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,22 @@ type LocalVerificationTests (output:ITestOutputHelper) =
this.Expect "ItemUpdate21" []
this.Expect "ItemUpdate22" []


[<Fact>]
member this.``Conjugation verification`` () =
this.Expect "ValidConjugation1" []
this.Expect "ValidConjugation2" []
this.Expect "ValidConjugation3" []
this.Expect "ValidConjugation4" []
this.Expect "ValidConjugation5" []
this.Expect "ValidConjugation6" []
this.Expect "ValidConjugation7" []
this.Expect "ValidConjugation8" []
this.Expect "InvalidConjugation1" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation2" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation3" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation4" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation5" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation6" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation7" [Error ErrorCode.InvalidReassignmentInApplyBlock]
this.Expect "InvalidConjugation8" [Error ErrorCode.InvalidReassignmentInApplyBlock]
189 changes: 189 additions & 0 deletions src/QsCompiler/Tests.Compiler/TestCases/LocalVerification.qs
Original file line number Diff line number Diff line change
Expand Up @@ -496,4 +496,193 @@ namespace Microsoft.Quantum.Testing.LocalVerification {
let _ = (OpPairArr([OpPair(arg, arg)]))::Array[0] w/ Op1 <- arg;
}


// conjugations

operation ValidConjugation1 () : Unit {
mutable foo = 1;
within {}
apply {
set foo = 10;
}
}

operation ValidConjugation2 () : Unit {
mutable foo = 1;
mutable bar = -1;
within {
GenericAdjointable(bar);
}
apply {
set foo = 10;
}
}


operation ValidConjugation3 () : Unit {
mutable foo = 1;
within {}
apply {
set (_, foo) = (1, 10);
}
}

operation ValidConjugation4 () : Unit {
mutable foo = 1;
mutable bar = -1;
within {
GenericAdjointable(bar);
}
apply {
set (_, foo) = (1, 10);
}
}

operation ValidConjugation5 () : Unit {
mutable foo = 1;
mutable bar = -1;
within {
let _ = bar;
}
apply {
set (_, foo) = (1, 10);
}
}

operation ValidConjugation6 () : Unit {
mutable foo = 1;
mutable bar = -1;
within {
let _ = bar;
}
apply {
mutable nrIter = 0;
repeat {
set nrIter += 1;
GenericOperation();
}
until (false);
}
}

operation ValidConjugation7 (cond : Bool) : Unit {
mutable foo = 1;
within {
if (cond) {
fail "{foo}";
}
}
apply {
if (not cond) {
set (_, (foo, _)) = (1, (10, ""));
}
}
}

operation ValidConjugation8 (cond : Bool) : Unit {
mutable foo = 1;
within {
for (i in 1 .. 10) {
GenericAdjointable(i, (i, foo));
}
}
apply {
repeat {}
until (cond)
fixup {}
}
}


operation InvalidConjugation1 () : Unit {
mutable foo = 1;
within {
GenericAdjointable(foo);
}
apply {
set foo = 10;
}
}

operation InvalidConjugation2 () : Unit {
mutable foo = 1;
within {
GenericAdjointable($"{foo}");
}
apply {
set foo = 10;
}
}

operation InvalidConjugation3 () : Unit {
mutable foo = 1;
within {
let _ = foo;
}
apply {
set foo = 10;
}
}

operation InvalidConjugation4 () : Unit {
mutable foo = 1;
within {
let _ = foo;
}
apply {
set (_, foo) = (1, 10);
}
}

operation InvalidConjugation5 () : Unit {
mutable foo = 1;
within {
if (foo + 1 > 0) {}
}
apply {
set (_, foo) = (1, 10);
}
}

operation InvalidConjugation6 (cond : Bool) : Unit {
mutable foo = 1;
within {
if (cond) {
fail $"{foo}";
}
}
apply {
set (_, (foo, _)) = (1, (10, ""));
}
}

operation InvalidConjugation7 (cond : Bool) : Unit {
mutable foo = 1;
within {
if (cond) {
fail $"{foo}";
}
}
apply {
if (not cond) {
set (_, (foo, _)) = (1, (10, ""));
}
}
}

operation InvalidConjugation8 (cond : Bool) : Unit {
mutable foo = 1;
within {
for (i in 1 .. 10) {
GenericAdjointable(i, (i, foo));
}
}
apply {
repeat {}
until (cond)
fixup {
set (_, (foo, _)) = (1, (10, ""));
}
}
}
}
Loading

0 comments on commit 6fbd0c5

Please sign in to comment.