diff --git a/src/Core/ExecutionPathTracer/ExecutionPath.cs b/src/Core/ExecutionPathTracer/ExecutionPath.cs
new file mode 100644
index 0000000000..1cc533db6d
--- /dev/null
+++ b/src/Core/ExecutionPathTracer/ExecutionPath.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Microsoft.Quantum.IQSharp.Core.ExecutionPathTracer
+{
+ ///
+ /// Represents the qubit resources and operations traced out in an execution path of a Q# operation.
+ ///
+ public class ExecutionPath
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// A list of that represents the declared qubits used in the execution path.
+ ///
+ ///
+ /// A list of that represents the operations used in the execution path.
+ ///
+ public ExecutionPath(IEnumerable qubits, IEnumerable operations)
+ {
+ this.Qubits = qubits;
+ this.Operations = operations;
+ }
+
+ ///
+ /// A list of that represents the declared qubits used in the execution path.
+ ///
+ [JsonProperty("qubits")]
+ public IEnumerable Qubits { get; }
+
+ ///
+ /// A list of that represents the operations used in the execution path.
+ ///
+ [JsonProperty("operations")]
+ public IEnumerable Operations { get; }
+
+ ///
+ /// Serializes into its JSON representation.
+ ///
+ ///
+ /// Pretty prints the JSON (i.e. with white space and indents) if true.
+ ///
+ public string ToJson(bool prettyPrint = false) =>
+ JsonConvert.SerializeObject(this,
+ (prettyPrint) ? Formatting.Indented : Formatting.None,
+ new JsonSerializerSettings
+ {
+ NullValueHandling = NullValueHandling.Ignore,
+ }
+ );
+ }
+
+ ///
+ /// Represents a qubit resource used in an execution path.
+ ///
+ public class QubitDeclaration
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Id of qubit.
+ ///
+ ///
+ /// Number of associated classical registers.
+ ///
+ public QubitDeclaration(int id, int numChildren = 0)
+ {
+ this.Id = id;
+ this.NumChildren = numChildren;
+ }
+
+ ///
+ /// Id of qubit.
+ ///
+ [JsonProperty("id")]
+ public int Id { get; }
+
+ ///
+ /// Number of associated classical registers.
+ ///
+ [JsonProperty("numChildren")]
+ public int NumChildren { get; }
+
+ ///
+ /// Used by to determine if
+ /// should be included in the JSON serialization.
+ ///
+ public bool ShouldSerializeNumChildren() => NumChildren > 0;
+ }
+
+ ///
+ /// Represents an operation used in an execution path.
+ ///
+ public class Operation
+ {
+ ///
+ /// Label of gate.
+ ///
+ [JsonProperty("gate")]
+ public string Gate { get; set; } = "";
+
+ ///
+ /// Arguments (except types) provided to gate that
+ /// will be displayed by the visualizer.
+ ///
+ [JsonProperty("displayArgs")]
+ public string? DisplayArgs { get; set; }
+
+ ///
+ /// Group of operations for each classical branch.
+ ///
+ ///
+ /// Currently not used as this is intended for classically-controlled operations.
+ ///
+ [JsonProperty("children")]
+ public IEnumerable>? Children { get; set; }
+
+ ///
+ /// True if operation is a controlled operations.
+ ///
+ [JsonProperty("controlled")]
+ public bool Controlled { get; set; }
+
+ ///
+ /// True if operation is an adjoint operations.
+ ///
+ [JsonProperty("adjoint")]
+ public bool Adjoint { get; set; }
+
+ ///
+ /// List of control registers.
+ ///
+ [JsonProperty("controls")]
+ public IEnumerable Controls { get; set; } = new List();
+
+ ///
+ /// List of target registers.
+ ///
+ [JsonProperty("targets")]
+ public IEnumerable Targets { get; set; } = new List();
+ }
+}
diff --git a/src/Core/ExecutionPathTracer/ExecutionPathTracer.cs b/src/Core/ExecutionPathTracer/ExecutionPathTracer.cs
new file mode 100644
index 0000000000..3944f2c475
--- /dev/null
+++ b/src/Core/ExecutionPathTracer/ExecutionPathTracer.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Quantum.Simulation.Core;
+
+#nullable enable
+
+namespace Microsoft.Quantum.IQSharp.Core.ExecutionPathTracer
+{
+ ///
+ /// Traces through the operations in a given execution path of a Q# program by hooking on
+ /// to a simulator via the event listeners and
+ /// , and generates the corresponding .
+ ///
+ public class ExecutionPathTracer
+ {
+ private int currentDepth = 0;
+ private int renderDepth;
+ private IDictionary qubitRegisters = new Dictionary();
+ private IDictionary> classicalRegisters = new Dictionary>();
+ private List operations = new List();
+
+ ///
+ /// Initializes a new instance of the class with the depth to render operations at.
+ ///
+ ///
+ /// The depth at which to render operations.
+ ///
+ public ExecutionPathTracer(int depth = 1) => this.renderDepth = depth + 1;
+
+ ///
+ /// Returns the generated .
+ ///
+ public ExecutionPath GetExecutionPath() =>
+ new ExecutionPath(
+ this.qubitRegisters.Keys
+ .OrderBy(k => k)
+ .Select(k => new QubitDeclaration(k, (this.classicalRegisters.ContainsKey(k))
+ ? this.classicalRegisters[k].Count
+ : 0
+ )),
+ this.operations
+ );
+
+ ///
+ /// Provides the event listener to listen to
+ /// 's
+ /// OnOperationStart event.
+ ///
+ public void OnOperationStartHandler(ICallable operation, IApplyData arguments)
+ {
+ this.currentDepth++;
+
+ // Parse operations at specified depth
+ if (this.currentDepth == this.renderDepth)
+ {
+ var metadata = operation.GetRuntimeMetadata(arguments);
+ var parsedOp = this.MetadataToOperation(metadata);
+ if (parsedOp != null) this.operations.Add(parsedOp);
+ }
+ }
+
+ ///
+ /// Provides the event listener to listen to
+ /// 's
+ /// OnOperationEnd event.
+ ///
+ public void OnOperationEndHandler(ICallable operation, IApplyData result) => this.currentDepth--;
+
+ ///
+ /// Retrieves the associated with the given or create a new
+ /// one if it doesn't exist.
+ ///
+ private QubitRegister GetQubitRegister(Qubit qubit) =>
+ this.qubitRegisters.GetOrCreate(qubit.Id, new QubitRegister(qubit.Id));
+
+ private List GetQubitRegisters(IEnumerable qubits) =>
+ qubits.Select(this.GetQubitRegister).ToList();
+
+ ///
+ /// Creates a new and associate it with the given .
+ ///
+ private ClassicalRegister CreateClassicalRegister(Qubit measureQubit)
+ {
+ var qId = measureQubit.Id;
+ var cId = this.classicalRegisters.GetOrCreate(qId).Count;
+
+ var register = new ClassicalRegister(qId, cId);
+
+ // Add classical register under the given qubit id
+ this.classicalRegisters[qId].Add(register);
+
+ return register;
+ }
+
+ ///
+ /// Retrieves the most recent associated with the given .
+ ///
+ ///
+ /// Currently not used as this is intended for classically-controlled operations.
+ ///
+ private ClassicalRegister GetClassicalRegister(Qubit controlQubit)
+ {
+ var qId = controlQubit.Id;
+ if (!this.classicalRegisters.ContainsKey(qId) || this.classicalRegisters[qId].Count == 0)
+ {
+ throw new Exception("No classical registers found for qubit {qId}.");
+ }
+
+ // Get most recent measurement on given control qubit
+ var cId = this.classicalRegisters[qId].Count - 1;
+ return this.classicalRegisters[qId][cId];
+ }
+
+ ///
+ /// Parse into its corresponding .
+ ///
+ private Operation? MetadataToOperation(RuntimeMetadata? metadata)
+ {
+ if (metadata == null) return null;
+
+ var op = new Operation()
+ {
+ Gate = metadata.Label,
+ DisplayArgs = (metadata.FormattedNonQubitArgs.Length > 0) ? metadata.FormattedNonQubitArgs : null,
+ Children = metadata.Children?.Select(child => child.Select(this.MetadataToOperation).WhereNotNull()),
+ Controlled = metadata.IsControlled,
+ Adjoint = metadata.IsAdjoint,
+ Controls = this.GetQubitRegisters(metadata.Controls),
+ Targets = this.GetQubitRegisters(metadata.Targets),
+ };
+
+ // Create classical registers for measurement operations
+ if (metadata.IsMeasurement)
+ {
+ var measureQubit = metadata.Targets.ElementAt(0);
+ var clsReg = this.CreateClassicalRegister(measureQubit);
+ // TODO: Change this to using IsMeasurement
+ op.Gate = "measure";
+ op.Controls = op.Targets;
+ op.Targets = new List() { clsReg };
+ }
+
+ return op;
+ }
+ }
+}
diff --git a/src/Core/ExecutionPathTracer/Extensions.cs b/src/Core/ExecutionPathTracer/Extensions.cs
new file mode 100644
index 0000000000..f836620843
--- /dev/null
+++ b/src/Core/ExecutionPathTracer/Extensions.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Quantum.Simulation.Common;
+using Microsoft.Quantum.Simulation.Core;
+
+namespace Microsoft.Quantum.IQSharp.Core.ExecutionPathTracer
+{
+ ///
+ /// Extension methods to be used with and by .
+ ///
+ public static class Extensions
+ {
+ ///
+ /// Attaches event listeners to the simulator to generate
+ /// the of the operation performed by the simulator.
+ ///
+ public static T WithExecutionPathTracer(this T sim, ExecutionPathTracer tracer)
+ where T : SimulatorBase
+ {
+ sim.OnOperationStart += tracer.OnOperationStartHandler;
+ sim.OnOperationEnd += tracer.OnOperationEndHandler;
+ return sim;
+ }
+
+ ///
+ /// Gets the value associated with the specified key and creates a new entry with the defaultVal if
+ /// the key doesn't exist.
+ ///
+ public static TValue GetOrCreate(this IDictionary dict, TKey key, TValue defaultVal)
+ {
+ TValue val;
+ if (!dict.TryGetValue(key, out val))
+ {
+ val = defaultVal;
+ dict.Add(key, val);
+ }
+ return val;
+ }
+
+ ///
+ /// Gets the value associated with the specified key and creates a new entry of the default type if
+ /// the key doesn't exist.
+ ///
+ public static TValue GetOrCreate(this IDictionary dict, TKey key)
+ where TValue : new() => dict.GetOrCreate(key, new TValue());
+ }
+}
diff --git a/src/Core/ExecutionPathTracer/Register.cs b/src/Core/ExecutionPathTracer/Register.cs
new file mode 100644
index 0000000000..a3560b73a3
--- /dev/null
+++ b/src/Core/ExecutionPathTracer/Register.cs
@@ -0,0 +1,90 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Serialization;
+
+namespace Microsoft.Quantum.IQSharp.Core.ExecutionPathTracer
+{
+ ///
+ /// Enum for the 2 types of registers: Qubit and Classical.
+ ///
+ public enum RegisterType
+ {
+ ///
+ /// Qubit register that holds a qubit.
+ ///
+ Qubit,
+ ///
+ /// Classical register that holds a classical bit.
+ ///
+ Classical,
+ }
+
+ ///
+ /// Represents a register used by an .
+ ///
+ public class Register
+ {
+ ///
+ /// Type of register.
+ ///
+ [JsonProperty("type")]
+ public virtual RegisterType Type { get; }
+
+ ///
+ /// Qubit id of register.
+ ///
+ [JsonProperty("qId")]
+ public virtual int QId { get; protected set; }
+
+ ///
+ /// Classical bit id of register. null if register is a qubit register.
+ ///
+ [JsonProperty("cId")]
+ public virtual int? CId { get; protected set; }
+ }
+
+ ///
+ /// Represents a qubit register used by an .
+ ///
+ public class QubitRegister : Register
+ {
+ ///
+ /// Creates a new with the given qubit id.
+ ///
+ ///
+ /// Id of qubit register.
+ ///
+ public QubitRegister(int qId) => this.QId = qId;
+
+ ///
+ public override RegisterType Type => RegisterType.Qubit;
+ }
+
+ ///
+ /// Represents a classical register used by an .
+ ///
+ public class ClassicalRegister : Register
+ {
+ ///
+ /// Creates a new with the given qubit id and classical bit id.
+ ///
+ ///
+ /// Id of qubit register.
+ ///
+ ///
+ /// Id of classical register associated with the given qubit id.
+ ///
+ public ClassicalRegister(int qId, int cId)
+ {
+ this.QId = qId;
+ this.CId = cId;
+ }
+
+ ///
+ public override RegisterType Type => RegisterType.Classical;
+ }
+}
diff --git a/src/Kernel/Extensions.cs b/src/Kernel/Extensions.cs
index 057ccecde8..1fd81e18e6 100644
--- a/src/Kernel/Extensions.cs
+++ b/src/Kernel/Extensions.cs
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Jupyter.Core;
using Microsoft.Quantum.IQSharp.Jupyter;
diff --git a/src/Kernel/client/ExecutionPathVisualizer/executionPath.ts b/src/Kernel/client/ExecutionPathVisualizer/executionPath.ts
index 314230fb84..eb74cb57f6 100644
--- a/src/Kernel/client/ExecutionPathVisualizer/executionPath.ts
+++ b/src/Kernel/client/ExecutionPathVisualizer/executionPath.ts
@@ -25,8 +25,8 @@ export interface Qubit {
export interface Operation {
/** Gate label. */
gate: string;
- /** Gate arguments as string. */
- argStr?: string,
+ /** Formatted gate arguments to be displayed. */
+ displayArgs?: string,
/** Classically-controlled gates.
* - children[0]: gates when classical control bit is 0.
* - children[1]: gates when classical control bit is 1.
diff --git a/src/Kernel/client/ExecutionPathVisualizer/formatters/gateFormatter.ts b/src/Kernel/client/ExecutionPathVisualizer/formatters/gateFormatter.ts
index 5132866b57..ca2b22a3d8 100644
--- a/src/Kernel/client/ExecutionPathVisualizer/formatters/gateFormatter.ts
+++ b/src/Kernel/client/ExecutionPathVisualizer/formatters/gateFormatter.ts
@@ -42,12 +42,12 @@ const formatGates = (opsMetadata: Metadata[]): string => {
* @returns SVG representation of gate.
*/
const _formatGate = (metadata: Metadata): string => {
- const { type, x, controlsY, targetsY, label, argStr, width } = metadata;
+ const { type, x, controlsY, targetsY, label, displayArgs, width } = metadata;
switch (type) {
case GateType.Measure:
return _measure(x, controlsY[0], targetsY[0]);
case GateType.Unitary:
- return _unitary(label, x, targetsY, width, argStr);
+ return _unitary(label, x, targetsY, width, displayArgs);
case GateType.Swap:
if (controlsY.length > 0) return _controlledGate(metadata);
else return _swap(x, targetsY);
@@ -89,12 +89,12 @@ const _measure = (x: number, qy: number, cy: number): string => {
* @param x x coord of gate.
* @param y Array of y coords of registers acted upon by gate.
* @param width Width of gate.
- * @param argStr Arguments passed in to gate.
+ * @param displayArgs Arguments passed in to gate.
* @param renderDashedLine If true, draw dashed lines between non-adjacent unitaries.
*
* @returns SVG representation of unitary gate.
*/
-const _unitary = (label: string, x: number, y: number[], width: number, argStr?: string, renderDashedLine: boolean = true): string => {
+const _unitary = (label: string, x: number, y: number[], width: number, displayArgs?: string, renderDashedLine: boolean = true): string => {
if (y.length === 0) return "";
// Sort y in ascending order
@@ -116,7 +116,7 @@ const _unitary = (label: string, x: number, y: number[], width: number, argStr?:
const unitaryBoxes: string[] = regGroups.map((group: number[]) => {
const maxY: number = group[group.length - 1], minY: number = group[0];
const height: number = maxY - minY + gateHeight;
- return _unitaryBox(label, x, minY, width, height, argStr);
+ return _unitaryBox(label, x, minY, width, height, displayArgs);
});
// Draw dashed line between disconnected unitaries
@@ -135,19 +135,19 @@ const _unitary = (label: string, x: number, y: number[], width: number, argStr?:
* @param y y coord of gate.
* @param width Width of gate.
* @param height Height of gate.
- * @param argStr Arguments passed in to gate.
+ * @param displayArgs Arguments passed in to gate.
*
* @returns SVG representation of unitary box.
*/
-const _unitaryBox = (label: string, x: number, y: number, width: number, height: number = gateHeight, argStr?: string): string => {
+const _unitaryBox = (label: string, x: number, y: number, width: number, height: number = gateHeight, displayArgs?: string): string => {
y -= gateHeight / 2;
const uBox: string = box(x - width / 2, y, width, height);
- const labelY = y + height / 2 - ((argStr == null) ? 0 : 7);
+ const labelY = y + height / 2 - ((displayArgs == null) ? 0 : 7);
const labelText: string = text(label, x, labelY);
const elems = [uBox, labelText];
- if (argStr != null) {
+ if (displayArgs != null) {
const argStrY = y + height / 2 + 8;
- const argText: string = text(argStr, x, argStrY, argsFontSize);
+ const argText: string = text(displayArgs, x, argStrY, argsFontSize);
elems.push(argText);
}
const svg: string = group(elems);
@@ -194,7 +194,7 @@ const _cross = (x: number, y: number): string => {
*/
const _controlledGate = (metadata: Metadata): string => {
const targetGateSvgs: string[] = [];
- const { type, x, controlsY, targetsY, label, argStr, width } = metadata;
+ const { type, x, controlsY, targetsY, label, displayArgs, width } = metadata;
// Get SVG for target gates
switch (type) {
case GateType.Cnot:
@@ -204,7 +204,7 @@ const _controlledGate = (metadata: Metadata): string => {
targetsY.forEach(y => targetGateSvgs.push(_cross(x, y)));
break;
case GateType.ControlledUnitary:
- targetGateSvgs.push(_unitary(label, x, targetsY, width, argStr, false));
+ targetGateSvgs.push(_unitary(label, x, targetsY, width, displayArgs, false));
break;
default:
throw new Error(`ERROR: Unrecognized gate: ${label} of type ${type}`);
diff --git a/src/Kernel/client/ExecutionPathVisualizer/metadata.ts b/src/Kernel/client/ExecutionPathVisualizer/metadata.ts
index e436d89722..2fe9bd7619 100644
--- a/src/Kernel/client/ExecutionPathVisualizer/metadata.ts
+++ b/src/Kernel/client/ExecutionPathVisualizer/metadata.ts
@@ -16,7 +16,7 @@ export interface Metadata {
/** Gate label. */
label: string;
/** Gate arguments as string. */
- argStr?: string,
+ displayArgs?: string,
/** Gate width. */
width: number;
/** Classically-controlled gates.
diff --git a/src/Kernel/client/ExecutionPathVisualizer/process.ts b/src/Kernel/client/ExecutionPathVisualizer/process.ts
index 0fce86488e..14c94f8104 100644
--- a/src/Kernel/client/ExecutionPathVisualizer/process.ts
+++ b/src/Kernel/client/ExecutionPathVisualizer/process.ts
@@ -185,7 +185,7 @@ const _opToMetadata = (op: Operation | null, registers: RegisterMap): Metadata =
if (op == null) return metadata;
- let { gate, argStr, controlled, adjoint, controls, targets, children } = op;
+ let { gate, displayArgs, controlled, adjoint, controls, targets, children } = op;
// Set y coords
metadata.controlsY = controls.map(reg => _getRegY(reg, registers));
@@ -233,7 +233,7 @@ const _opToMetadata = (op: Operation | null, registers: RegisterMap): Metadata =
if (adjoint && metadata.label.length > 0) metadata.label += "'";
// If gate has extra arguments, display them
- if (argStr != null) metadata.argStr = argStr;
+ if (displayArgs != null) metadata.displayArgs = displayArgs;
// Set gate width
metadata.width = getGateWidth(metadata);
diff --git a/src/Kernel/client/ExecutionPathVisualizer/utils.ts b/src/Kernel/client/ExecutionPathVisualizer/utils.ts
index 44d8515b23..2468d514d3 100644
--- a/src/Kernel/client/ExecutionPathVisualizer/utils.ts
+++ b/src/Kernel/client/ExecutionPathVisualizer/utils.ts
@@ -14,7 +14,7 @@ import {
*
* @returns Width of given gate (in pixels).
*/
-const getGateWidth = ({ type, label, argStr, width }: Metadata): number => {
+const getGateWidth = ({ type, label, displayArgs, width }: Metadata): number => {
switch (type) {
case GateType.ClassicalControlled:
// Already computed before.
@@ -25,7 +25,7 @@ const getGateWidth = ({ type, label, argStr, width }: Metadata): number => {
return minGateWidth;
default:
const labelWidth = _getStringWidth(label);
- const argsWidth = (argStr != null) ? _getStringWidth(argStr, argsFontSize) : 0;
+ const argsWidth = (displayArgs != null) ? _getStringWidth(displayArgs, argsFontSize) : 0;
const textWidth = Math.max(labelWidth, argsWidth) + labelPadding * 2;
return Math.max(minGateWidth, textWidth);
}
diff --git a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/gateFormatter.test.ts b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/gateFormatter.test.ts
index 2a5a761ac5..014346aa4b 100644
--- a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/gateFormatter.test.ts
+++ b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/gateFormatter.test.ts
@@ -449,7 +449,7 @@ describe("Testing _formatGate", () => {
controlsY: [],
targetsY: [startY],
label: 'Ry',
- argStr: '(0.25)',
+ displayArgs: '(0.25)',
width: 52,
};
expect(_formatGate(metadata)).toMatchSnapshot();
@@ -473,7 +473,7 @@ describe("Testing _formatGate", () => {
controlsY: [],
targetsY: [startY, startY + registerHeight],
label: 'U',
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
width: 77,
};
expect(_formatGate(metadata)).toMatchSnapshot();
@@ -529,7 +529,7 @@ describe("Testing _formatGate", () => {
controlsY: [startY],
targetsY: [startY + registerHeight],
label: 'U',
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
width: 77,
};
expect(_formatGate(metadata)).toMatchSnapshot();
diff --git a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/process.test.ts b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/process.test.ts
index bd9107c075..b5a6870d2d 100644
--- a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/process.test.ts
+++ b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/process.test.ts
@@ -513,7 +513,7 @@ describe("Testing _opToMetadata", () => {
};
let op: Operation = {
gate: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
controlled: false,
adjoint: false,
controls: [],
@@ -525,7 +525,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [],
targetsY: [startY],
label: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
width: 52
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -533,7 +533,7 @@ describe("Testing _opToMetadata", () => {
// Test long argument
op = {
gate: "RX",
- argStr: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
+ displayArgs: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
controlled: false,
adjoint: false,
controls: [],
@@ -545,7 +545,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [],
targetsY: [startY],
label: "RX",
- argStr: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
+ displayArgs: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
width: 188
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -553,7 +553,7 @@ describe("Testing _opToMetadata", () => {
// Test controlled
op = {
gate: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
controlled: true,
adjoint: false,
controls: [{ type: RegisterType.Qubit, qId: 1 }],
@@ -565,7 +565,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [startY + registerHeight],
targetsY: [startY],
label: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
width: 52
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -578,7 +578,7 @@ describe("Testing _opToMetadata", () => {
};
let op: Operation = {
gate: "U",
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
controlled: false,
adjoint: false,
controls: [],
@@ -593,7 +593,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [],
targetsY: [startY, startY + registerHeight],
label: "U",
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
width: 77
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -601,7 +601,7 @@ describe("Testing _opToMetadata", () => {
// Test long argument
op = {
gate: "U",
- argStr: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
+ displayArgs: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
controlled: false,
adjoint: false,
controls: [],
@@ -616,7 +616,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [],
targetsY: [startY, startY + registerHeight],
label: "U",
- argStr: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
+ displayArgs: "(0.25, 1.0, 'foobar', (3.14, 6.67))",
width: 188
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -624,7 +624,7 @@ describe("Testing _opToMetadata", () => {
// Test controlled
op = {
gate: "U",
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
controlled: true,
adjoint: false,
controls: [{ type: RegisterType.Qubit, qId: 1 }],
@@ -639,7 +639,7 @@ describe("Testing _opToMetadata", () => {
controlsY: [startY + registerHeight],
targetsY: [startY, startY + registerHeight * 2],
label: "U",
- argStr: "('foo', 'bar')",
+ displayArgs: "('foo', 'bar')",
width: 77
};
expect(_opToMetadata(op, registers)).toEqual(metadata);
@@ -1192,7 +1192,7 @@ describe("Testing processOperations", () => {
},
{
gate: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
controlled: false,
adjoint: false,
controls: [],
@@ -1234,7 +1234,7 @@ describe("Testing processOperations", () => {
controlsY: [],
targetsY: [startY + registerHeight],
label: "RX",
- argStr: "(0.25)",
+ displayArgs: "(0.25)",
width: rxWidth,
}
];
diff --git a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/utils.test.ts b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/utils.test.ts
index 52c21c6f4c..6edea89911 100644
--- a/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/utils.test.ts
+++ b/src/Kernel/client/__tests__/ExecutionPathVisualizerTests/utils.test.ts
@@ -27,7 +27,7 @@ describe("Testing getGateWidth", () => {
expect(getGateWidth(Object.assign({ type: GateType.Unitary, label: 'zz' })))
.toEqual(minGateWidth));
test("unitary gate with arguments", () =>
- expect(getGateWidth(Object.assign({ type: GateType.Unitary, argStr: '(0.25)', label: 'RX' })))
+ expect(getGateWidth(Object.assign({ type: GateType.Unitary, displayArgs: '(0.25)', label: 'RX' })))
.toEqual(52));
test("invalid", () =>
expect(getGateWidth(Object.assign({ type: GateType.Invalid, label: '' })))
diff --git a/src/Kernel/tsconfig.json b/src/Kernel/tsconfig.json
index 2d8de5d0dc..1a6932e15a 100644
--- a/src/Kernel/tsconfig.json
+++ b/src/Kernel/tsconfig.json
@@ -12,6 +12,6 @@
"module": "AMD",
"moduleResolution": "node"
},
- "exclude": ["node_modules", "wwwroot", "client/__test__"],
+ "exclude": ["node_modules", "wwwroot", "client/__tests__"],
"include": ["client/**/*"]
}
diff --git a/src/Tests/ExecutionPathTracerTests.cs b/src/Tests/ExecutionPathTracerTests.cs
new file mode 100644
index 0000000000..fea5a8c3c4
--- /dev/null
+++ b/src/Tests/ExecutionPathTracerTests.cs
@@ -0,0 +1,521 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.Quantum.IQSharp;
+using Microsoft.Quantum.Simulation.Simulators;
+using Microsoft.Quantum.IQSharp.Core.ExecutionPathTracer;
+
+namespace Tests.IQSharp
+{
+ [TestClass]
+ public class IntrinsicTests
+ {
+ public Workspace InitWorkspace()
+ {
+ var ws = Startup.Create("Workspace.ExecutionPathTracer");
+ ws.Reload();
+ Assert.IsFalse(ws.HasErrors);
+ return ws;
+ }
+
+ public ExecutionPath GetExecutionPath(string name, int depth = 1)
+ {
+ var ws = InitWorkspace();
+ var op = ws.AssemblyInfo.Operations.SingleOrDefault(o => o.FullName == $"Tests.ExecutionPathTracer.{name}");
+ Assert.IsNotNull(op);
+
+ var tracer = new ExecutionPathTracer(depth);
+ using var qsim = new QuantumSimulator().WithExecutionPathTracer(tracer);
+ op.RunAsync(qsim, new Dictionary()).Wait();
+
+ return tracer.GetExecutionPath();
+ }
+
+
+ [TestMethod]
+ public void HTest()
+ {
+ var path = GetExecutionPath("HCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "H",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ // TODO: Remove Reset/ResetAll gates once we don't need to zero out qubits
+ new Operation()
+ {
+ Gate = "Reset",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void MTest()
+ {
+ var path = GetExecutionPath("MCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0, 1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "measure",
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new ClassicalRegister(0, 0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void CnotTest()
+ {
+ var path = GetExecutionPath("CnotCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new QubitRegister(1) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List() { new QubitRegister(0), new QubitRegister(1) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void CcnotTest()
+ {
+ var path = GetExecutionPath("CcnotCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ new QubitDeclaration(2),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0), new QubitRegister(2) },
+ Targets = new List() { new QubitRegister(1) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List()
+ {
+ new QubitRegister(0),
+ new QubitRegister(1),
+ new QubitRegister(2),
+ },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void SwapTest()
+ {
+ var path = GetExecutionPath("SwapCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "SWAP",
+ Targets = new List() { new QubitRegister(0), new QubitRegister(1) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void RxTest()
+ {
+ var path = GetExecutionPath("RxCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "Rx",
+ DisplayArgs = "(2)",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "Reset",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void AdjointHTest()
+ {
+ var path = GetExecutionPath("AdjointHCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "H",
+ Adjoint = true,
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "Reset",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void ControlledXTest()
+ {
+ var path = GetExecutionPath("ControlledXCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new QubitRegister(1) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List() { new QubitRegister(0), new QubitRegister(1) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+
+ // JSON should be the same as CNOT's
+ var path2 = GetExecutionPath("CnotCirc");
+ Assert.AreEqual(path.ToJson(), path2.ToJson());
+ }
+
+ [TestMethod]
+ public void ControlledAdjointSTest()
+ {
+ var path = GetExecutionPath("ControlledAdjointSCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "S",
+ Controlled = true,
+ Adjoint = true,
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new QubitRegister(1) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List() { new QubitRegister(0), new QubitRegister(1) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void FooTest()
+ {
+ var path = GetExecutionPath("FooCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "Foo",
+ DisplayArgs = "(2.1, (\"bar\"))",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void ControlledFooTest()
+ {
+ var path = GetExecutionPath("ControlledFooCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "Foo",
+ DisplayArgs = "(2.1, (\"bar\"))",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new QubitRegister(1) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void UnusedQubitTest()
+ {
+ var path = GetExecutionPath("UnusedQubitCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(2),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(2) },
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "Reset",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "Reset",
+ Targets = new List() { new QubitRegister(2) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void Depth2Test()
+ {
+ var path = GetExecutionPath("Depth2Circ", 2);
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0, 1),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "H",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "X",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "H",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "measure",
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new ClassicalRegister(0, 0) },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void PartialOpTest()
+ {
+ var path = GetExecutionPath("PartialOpCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0),
+ new QubitDeclaration(1),
+ new QubitDeclaration(2),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "H",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0), new QubitRegister(1) },
+ Targets = new List() { new QubitRegister(2) },
+ },
+ new Operation()
+ {
+ Gate = "Ry",
+ DisplayArgs = "(2.5)",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List() {
+ new QubitRegister(0),
+ new QubitRegister(1),
+ new QubitRegister(2),
+ },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void EmptyTest()
+ {
+ var path = GetExecutionPath("EmptyCirc");
+ var qubits = new QubitDeclaration[] { };
+ var operations = new Operation[] { };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+
+ [TestMethod]
+ public void BigTest()
+ {
+ var path = GetExecutionPath("BigCirc");
+ var qubits = new QubitDeclaration[]
+ {
+ new QubitDeclaration(0, 1),
+ new QubitDeclaration(1),
+ new QubitDeclaration(2),
+ };
+ var operations = new Operation[]
+ {
+ new Operation()
+ {
+ Gate = "H",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "Ry",
+ DisplayArgs = "(2.5)",
+ Targets = new List() { new QubitRegister(1) },
+ },
+ new Operation()
+ {
+ Gate = "Bar",
+ DisplayArgs = "((1, 2.1), (\"foo\"))",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "X",
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0), new QubitRegister(1) },
+ Targets = new List() { new QubitRegister(2) },
+ },
+ new Operation()
+ {
+ Gate = "X",
+ Controlled = true,
+ Controls = new List() { new QubitRegister(0), new QubitRegister(1) },
+ Targets = new List() { new QubitRegister(2) },
+ },
+ new Operation()
+ {
+ Gate = "Bar",
+ DisplayArgs = "((1, 2.1), (\"foo\"))",
+ Controlled = true,
+ Adjoint = true,
+ Controls = new List() { new QubitRegister(2) },
+ Targets = new List() { new QubitRegister(0) },
+ },
+ new Operation()
+ {
+ Gate = "measure",
+ Controls = new List() { new QubitRegister(0) },
+ Targets = new List() { new ClassicalRegister(0, 0) },
+ },
+ new Operation()
+ {
+ Gate = "ResetAll",
+ Targets = new List() {
+ new QubitRegister(0),
+ new QubitRegister(1),
+ new QubitRegister(2),
+ },
+ },
+ };
+ var expected = new ExecutionPath(qubits, operations);
+ Assert.AreEqual(expected.ToJson(), path.ToJson());
+ }
+ }
+}
diff --git a/src/Tests/Tests.IQsharp.csproj b/src/Tests/Tests.IQsharp.csproj
index 6b8f79b98e..90536f1c09 100644
--- a/src/Tests/Tests.IQsharp.csproj
+++ b/src/Tests/Tests.IQsharp.csproj
@@ -48,6 +48,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
diff --git a/src/Tests/Workspace.ExecutionPathTracer/Intrinsic.qs b/src/Tests/Workspace.ExecutionPathTracer/Intrinsic.qs
new file mode 100644
index 0000000000..3811173584
--- /dev/null
+++ b/src/Tests/Workspace.ExecutionPathTracer/Intrinsic.qs
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Tests.ExecutionPathTracer {
+
+ open Microsoft.Quantum.Intrinsic;
+
+ operation HCirc() : Unit {
+ using (q = Qubit()) {
+ H(q);
+ Reset(q);
+ }
+ }
+
+ operation MCirc() : Unit {
+ using (q = Qubit()) {
+ let res = M(q);
+ }
+ }
+
+ operation CnotCirc() : Unit {
+ using (qs = Qubit[2]) {
+ CNOT(qs[0], qs[1]);
+ ResetAll(qs);
+ }
+ }
+
+ operation CcnotCirc() : Unit {
+ using (qs = Qubit[3]) {
+ CCNOT(qs[0], qs[2], qs[1]);
+ ResetAll(qs);
+ }
+ }
+
+ operation SwapCirc() : Unit {
+ using (qs = Qubit[2]) {
+ SWAP(qs[0], qs[1]);
+ }
+ }
+
+ operation RxCirc() : Unit {
+ using (q = Qubit()) {
+ Rx(2.0, q);
+ Reset(q);
+ }
+ }
+
+ operation AdjointHCirc() : Unit {
+ using (q = Qubit()) {
+ Adjoint H(q);
+ Reset(q);
+ }
+ }
+
+ operation ControlledXCirc() : Unit {
+ using (qs = Qubit[2]) {
+ Controlled X([qs[0]], qs[1]);
+ ResetAll(qs);
+ }
+ }
+
+ operation ControlledAdjointSCirc() : Unit {
+ using (qs = Qubit[2]) {
+ Controlled Adjoint S([qs[0]], qs[1]);
+ ResetAll(qs);
+ }
+ }
+
+ // Custom operation
+ operation Foo(theta : Double, (qubit : Qubit, bar : String)) : Unit
+ is Adj + Ctl {
+ }
+
+ operation FooCirc() : Unit {
+ using (q = Qubit()) {
+ Foo(2.1, (q, "bar"));
+ }
+ }
+
+ operation ControlledFooCirc() : Unit {
+ using (qs = Qubit[2]) {
+ Controlled Foo([qs[0]], (2.1, (qs[1], "bar")));
+ }
+ }
+
+ operation UnusedQubitCirc() : Unit {
+ using (qs = Qubit[3]) {
+ CNOT(qs[2], qs[0]);
+ Reset(qs[0]);
+ Reset(qs[2]);
+ }
+ }
+
+ operation EmptyCirc() : Unit {
+ using (qs = Qubit[3]) {
+ }
+ }
+
+ operation FooBar(q : Qubit) : Unit {
+ H(q);
+ X(q);
+ H(q);
+ }
+
+ operation Depth2Circ() : Unit {
+ using (q = Qubit()) {
+ FooBar(q);
+ Reset(q);
+ }
+ }
+
+ operation PartialOpCirc() : Unit {
+ using (qs = Qubit[3]) {
+ (Controlled H(qs[0..1], _))(qs[2]);
+ ((Ry(_, _))(2.5, _))(qs[0]);
+ ResetAll(qs);
+ }
+ }
+
+ operation Bar((alpha : Double, beta : Double), (q : Qubit, name : String)) : Unit
+ is Adj + Ctl {
+ }
+
+ operation BigCirc() : Unit {
+ using (qs = Qubit[3]) {
+ H(qs[0]);
+ Ry(2.5, qs[1]);
+ Bar((1.0, 2.1), (qs[0], "foo"));
+ X(qs[0]);
+ CCNOT(qs[0], qs[1], qs[2]);
+ Controlled CNOT([qs[0]], (qs[1], qs[2]));
+ Controlled Adjoint Bar([qs[2]], ((1.0, 2.1), (qs[0], "foo")));
+ let res = M(qs[0]);
+ ResetAll(qs);
+ }
+ }
+
+}
+
+
diff --git a/src/Tests/Workspace.ExecutionPathTracer/Measurement.qs b/src/Tests/Workspace.ExecutionPathTracer/Measurement.qs
new file mode 100644
index 0000000000..01efa8d5f8
--- /dev/null
+++ b/src/Tests/Workspace.ExecutionPathTracer/Measurement.qs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Tests.ExecutionPathTracer {
+
+ open Microsoft.Quantum.Measurement;
+
+ operation MResetXCirc() : Unit {
+ using (q = Qubit()) {
+ let res = MResetX(q);
+ }
+ }
+
+ operation MResetYCirc() : Unit {
+ using (q = Qubit()) {
+ let res = MResetY(q);
+ }
+ }
+
+ operation MResetZCirc() : Unit {
+ using (q = Qubit()) {
+ let res = MResetZ(q);
+ }
+ }
+
+}
+
+