Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/ExecutionPathTracer/ExecutionPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ public class Operation
/// <summary>
/// Group of operations for each classical branch.
/// </summary>
/// <remarks>
/// Currently not used as this is intended for classically-controlled operations.
/// </remarks>
[JsonProperty("children")]
public IEnumerable<IEnumerable<Operation>>? Children { get; set; }

Expand All @@ -130,6 +127,12 @@ public class Operation
[JsonProperty("isMeasurement")]
public bool IsMeasurement { get; set; }

/// <summary>
/// True if operation is a classically-controlled operations.
/// </summary>
[JsonProperty("isConditional")]
public bool IsConditional { get; set; }

/// <summary>
/// True if operation is a controlled operations.
/// </summary>
Expand Down
16 changes: 14 additions & 2 deletions src/ExecutionPathTracer/ExecutionPathTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ public void OnOperationStartHandler(ICallable operation, IApplyData arguments)

var metadata = operation.GetRuntimeMetadata(arguments);

// If metadata is a composite operation (i.e. want to trace its components instead),
// If metadata is a composite/conditional operation (i.e. want to trace its components instead),
// we recursively create a tracer that traces its components instead
if (metadata != null && metadata.IsComposite)
if (metadata != null && (metadata.IsComposite || metadata.IsConditional))
{
var remainingDepth = this.renderDepth - this.currentDepth;
this.compositeTracer = new ExecutionPathTracer(remainingDepth);
Expand All @@ -81,6 +81,8 @@ public void OnOperationStartHandler(ICallable operation, IApplyData arguments)
this.currCompositeOp = operation;
// Set currentOperation to null so we don't render higher-depth operations unintentionally.
this.currentOperation = null;

if (metadata.IsConditional) this.currentOperation = this.MetadataToOperation(metadata);
return;
}

Expand Down Expand Up @@ -179,6 +181,15 @@ private void AddCompositeOperations()
if (this.compositeTracer == null)
throw new NullReferenceException("ERROR: compositeTracer not initialized.");

if (this.currentOperation != null && this.currentOperation.IsConditional)
{
var numChildren = this.compositeTracer.operations.Count();
if (numChildren != 2) throw new IndexOutOfRangeException($"ERROR: Found only {numChildren} children for conditional operation.");
this.currentOperation.Children = this.compositeTracer.operations
.Select(op => new List<Operation>() { op });
this.operations.Add(this.currentOperation);
return;
}
// The composite tracer has done its job and we retrieve the operations it traced
this.operations.AddRange(this.compositeTracer.operations);
}
Expand All @@ -202,6 +213,7 @@ private void AddCompositeOperations()
Gate = metadata.Label,
DisplayArgs = displayArgs,
Children = metadata.Children?.Select(child => child.Select(this.MetadataToOperation).WhereNotNull()),
IsConditional = metadata.IsConditional,
IsControlled = metadata.IsControlled,
IsAdjoint = metadata.IsAdjoint,
Controls = this.GetQubitRegisters(metadata.Controls),
Expand Down
43 changes: 43 additions & 0 deletions src/ExecutionPathTracer/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,50 @@

#nullable enable

using System;
using System.Collections.Generic;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.QuantumProcessor.Extensions;

namespace Microsoft.Quantum.IQSharp.ExecutionPathTracer
{
/// <summary>
/// Custom ApplyIfElse used by Tracer to overrides the default behaviour and executes both branches
/// of the conditional statement.
/// </summary>
public class TracerApplyIfElse : ApplyIfElseR<Qubit, Qubit>
{
private SimulatorBase Simulator { get; }

/// <summary>
/// Initializes a new instance of the <see cref="TracerApplyIfElse"/> class.
/// </summary>
public TracerApplyIfElse(SimulatorBase m) : base(m)
{
this.Simulator = m;
}

/// <inheritdoc />
public override Func<(Result, (ICallable, Qubit), (ICallable, Qubit)), QVoid> Body => (q) =>
{
(Result measurementResult, (ICallable onZero, Qubit one), (ICallable onOne, Qubit two)) = q;
onZero.Apply(one);
onOne.Apply(two);

return QVoid.Instance;
};

/// <inheritdoc />
public override RuntimeMetadata? GetRuntimeMetadata(IApplyData args)
{
var metadata = base.GetRuntimeMetadata(args);
if (metadata == null) throw new NullReferenceException($"Null RuntimeMetadata found for {this.ToString()}.");
metadata.IsComposite = true;
return metadata;
}
}

/// <summary>
/// Extension methods to be used with and by <see cref="ExecutionPathTracer"/>.
/// </summary>
Expand All @@ -22,6 +61,10 @@ public static T WithExecutionPathTracer<T>(this T sim, ExecutionPathTracer trace
{
sim.OnOperationStart += tracer.OnOperationStartHandler;
sim.OnOperationEnd += tracer.OnOperationEndHandler;
sim.Register(
typeof(ApplyIfElseR<Qubit, Qubit>),
typeof(TracerApplyIfElse)
);
return sim;
}

Expand Down
50 changes: 50 additions & 0 deletions src/Tests/ExecutionPathTracerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,56 @@ public void BigTest()
var expected = new ExecutionPath(qubits, operations);
Assert.AreEqual(expected.ToJson(), path.ToJson());
}

[TestMethod]
public void IfTest()
{
var path = GetExecutionPath("IfCirc");
var qubits = new QubitDeclaration[] { new QubitDeclaration(0, 1) };
var operations = new Operation[]
{
new Operation()
{
Gate = "M",
IsMeasurement = true,
Controls = new List<Register>() { new QubitRegister(0) },
Targets = new List<Register>() { new ClassicalRegister(0, 0) },
},
new Operation()
{
Gate = "ApplyIfElseR",
DisplayArgs = "(Zero, (X), (Z))",
Controls = new List<Register>() { new ClassicalRegister(0, 0) },
Targets = new List<Register>() { new QubitRegister(0) },
Children = new List<List<Operation>>()
{
new List<Operation>()
{
new Operation()
{
Gate = "X",
Targets = new List<Register>() { new QubitRegister(0) },
},
},
new List<Operation>()
{
new Operation()
{
Gate = "Z",
Targets = new List<Register>() { new QubitRegister(0) },
},
},
},
},
new Operation()
{
Gate = "Reset",
Targets = new List<Register>() { new QubitRegister(0) },
},
};
var expected = new ExecutionPath(qubits, operations);
Assert.AreEqual(expected.ToJson(), path.ToJson());
}
}

[TestClass]
Expand Down
9 changes: 9 additions & 0 deletions src/Tests/Workspace.ExecutionPathTracer/Circuits.qs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Tests.ExecutionPathTracer {

open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Simulation.QuantumProcessor.Extensions;

// Custom operation
operation Foo(theta : Double, (qubit : Qubit, bar : String)) : Unit
Expand Down Expand Up @@ -94,5 +95,13 @@ namespace Tests.ExecutionPathTracer {
ResetAll(qs);
}
}

operation IfCirc() : Unit {
using (q = Qubit()) {
let res = M(q);
ApplyIfElseR(res, (X, q), (Z, q));
Reset(q);
}
}

}