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

First step to implementing classically-controlled gates #290

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
25 changes: 25 additions & 0 deletions src/ExecutionPathTracer/ExecutionPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ public QubitDeclaration(int id, int numChildren = 0)
public bool ShouldSerializeNumChildren() => NumChildren > 0;
}

/// <summary>
/// Conditions on when to render the given operation.
/// </summary>
public enum ConditionalRender
{
/** Always rendered. */
Always,
/** Render classically-controlled operation when measurement is a zero. */
OnZero,
/** Render classically-controlled operation when measurement is a one. */
OnOne,
}

/// <summary>
/// Represents an operation used in an execution path.
/// </summary>
Expand Down Expand Up @@ -128,6 +141,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 All @@ -152,6 +171,12 @@ public class Operation
[JsonProperty("targets")]
public IEnumerable<Register> Targets { get; set; } = new List<Register>();

/// <summary>
/// Specify conditions on when to render operation.
/// </summary>
[JsonProperty("conditionalRender")]
public ConditionalRender? ConditionalRender;

/// <summary>
/// Dictionary of data attributes to add to rendered gate element.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions src/ExecutionPathTracer/ExecutionPathTracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ public void OnOperationEndHandler(ICallable operation, IApplyData result)
// Add operation to parent operation's children
parentOp.Children = (parentOp.Children ?? ImmutableList<Operation>.Empty).Add(currentOperation);

// If parent op is a conditional statement, the first child is rendered onZero and the second onOne
if (parentOp.IsConditional)
{
if (parentOp.Children.Count() == 1) currentOperation.ConditionalRender = ConditionalRender.OnZero;
else currentOperation.ConditionalRender = ConditionalRender.OnOne;
} else if (parentOp.ConditionalRender != null)
{
// Inherit parent's render condition
currentOperation.ConditionalRender = parentOp.ConditionalRender;
}

// Add target qubits to parent
parentOp.Targets = parentOp.Targets
.Concat(currentOperation.Targets.Where(reg => reg is QubitRegister))
Expand Down Expand Up @@ -144,6 +155,7 @@ private ClassicalRegister GetClassicalRegister(Qubit controlQubit)
{
Gate = metadata.Label,
DisplayArgs = displayArgs,
IsConditional = metadata.IsConditional,
IsControlled = metadata.IsControlled,
IsAdjoint = metadata.IsAdjoint,
Controls = this.GetQubitRegisters(metadata.Controls),
Expand Down
34 changes: 34 additions & 0 deletions src/ExecutionPathTracer/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,41 @@

#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;
};
}

/// <summary>
/// Extension methods to be used with and by <see cref="ExecutionPathTracer"/>.
/// </summary>
Expand All @@ -22,6 +52,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
47 changes: 47 additions & 0 deletions src/Tests/ExecutionPathTracerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,53 @@ public void BigTest()
var expected = new ExecutionPath(qubits, operations);
AssertExecutionPathsEqual(expected, path);
}

[TestMethod]
public void IfTest()
{
var path = GetExecutionPath("IfCirc");
var qubits = new QubitDeclaration[] { new QubitDeclaration(0, 2) };
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 = ImmutableList<Operation>.Empty.AddRange(
new [] {
new Operation()
{
Gate = "X",
Targets = new List<Register>() { new QubitRegister(0) },
ConditionalRender = ConditionalRender.OnZero,
},
new Operation()
{
Gate = "Z",
Targets = new List<Register>() { new QubitRegister(0) },
ConditionalRender = ConditionalRender.OnOne,
},
}
)
},
new Operation()
{
Gate = "Reset",
Targets = new List<Register>() { new QubitRegister(0) },
},
};
var expected = new ExecutionPath(qubits, operations);
AssertExecutionPathsEqual(expected, path);
}
}

[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 @@ -85,4 +86,12 @@ namespace Tests.ExecutionPathTracer {
}
}

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

}