This repository was archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 55
Add ExecutionPathTracer to repo.
#195
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
8b287d4
Add ExecutionPathTracer to repo
9073759
Add WithExecutionPathTracer extension method to SimulatorBase
359e8d8
Respond to PR feedback
4907615
Use GetRuntimeMetadata
43b0b85
Remove ApplyToEach
10ef3cc
Add tests
bcd1e17
Use Newtonsoft instead of System.Text.Json
ca84324
Rename ArgStr to DisplayArgs
ef866f0
Clean up code
bc78e63
Fix typo in tsconfig
5096ba3
Fix tests
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| { | ||
| /// <summary> | ||
| /// Represents the qubit resources and operations traced out in an execution path of a Q# operation. | ||
| /// </summary> | ||
| public class ExecutionPath | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="ExecutionPathTracer"/> class. | ||
| /// </summary> | ||
| /// <param name="qubits"> | ||
| /// A list of <see cref="QubitDeclaration"/> that represents the declared qubits used in the execution path. | ||
| /// </param> | ||
| /// <param name="operations"> | ||
| /// A list of <see cref="Operation"/> that represents the operations used in the execution path. | ||
| /// </param> | ||
| public ExecutionPath(IEnumerable<QubitDeclaration> qubits, IEnumerable<Operation> operations) | ||
| { | ||
| this.Qubits = qubits; | ||
| this.Operations = operations; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// A list of <see cref="QubitDeclaration"/> that represents the declared qubits used in the execution path. | ||
| /// </summary> | ||
| [JsonProperty("qubits")] | ||
| public IEnumerable<QubitDeclaration> Qubits { get; } | ||
|
|
||
| /// <summary> | ||
| /// A list of <see cref="Operation"/> that represents the operations used in the execution path. | ||
| /// </summary> | ||
| [JsonProperty("operations")] | ||
| public IEnumerable<Operation> Operations { get; } | ||
|
|
||
| /// <summary> | ||
| /// Serializes <see cref="ExecutionPath"/> into its JSON representation. | ||
| /// </summary> | ||
| /// <param name="prettyPrint"> | ||
| /// Pretty prints the JSON (i.e. with white space and indents) if <c>true</c>. | ||
| /// </param> | ||
| public string ToJson(bool prettyPrint = false) => | ||
| JsonConvert.SerializeObject(this, | ||
| (prettyPrint) ? Formatting.Indented : Formatting.None, | ||
| new JsonSerializerSettings | ||
| { | ||
| NullValueHandling = NullValueHandling.Ignore, | ||
| } | ||
| ); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents a qubit resource used in an execution path. | ||
| /// </summary> | ||
| public class QubitDeclaration | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="QubitDeclaration"/> class. | ||
| /// </summary> | ||
| /// <param name="id"> | ||
| /// Id of qubit. | ||
| /// </param> | ||
| /// <param name="numChildren"> | ||
| /// Number of associated classical registers. | ||
| /// </param> | ||
| public QubitDeclaration(int id, int numChildren = 0) | ||
| { | ||
| this.Id = id; | ||
| this.NumChildren = numChildren; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Id of qubit. | ||
| /// </summary> | ||
| [JsonProperty("id")] | ||
| public int Id { get; } | ||
|
|
||
| /// <summary> | ||
| /// Number of associated classical registers. | ||
theRoughCode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// </summary> | ||
| [JsonProperty("numChildren")] | ||
| public int NumChildren { get; } | ||
|
|
||
| /// <summary> | ||
| /// Used by <see cref="Newtonsoft" /> to determine if <see cref="NumChildren" /> | ||
| /// should be included in the JSON serialization. | ||
| /// </summary> | ||
| public bool ShouldSerializeNumChildren() => NumChildren > 0; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Represents an operation used in an execution path. | ||
| /// </summary> | ||
| public class Operation | ||
| { | ||
| /// <summary> | ||
| /// Label of gate. | ||
| /// </summary> | ||
| [JsonProperty("gate")] | ||
| public string Gate { get; set; } = ""; | ||
|
|
||
| /// <summary> | ||
| /// Arguments (except <see cref="Qubit" /> types) provided to gate that | ||
| /// will be displayed by the visualizer. | ||
| /// </summary> | ||
| [JsonProperty("displayArgs")] | ||
| public string? DisplayArgs { get; set; } | ||
|
|
||
| /// <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; } | ||
|
|
||
| /// <summary> | ||
| /// True if operation is a controlled operations. | ||
| /// </summary> | ||
| [JsonProperty("controlled")] | ||
| public bool Controlled { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// True if operation is an adjoint operations. | ||
| /// </summary> | ||
| [JsonProperty("adjoint")] | ||
| public bool Adjoint { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// List of control registers. | ||
| /// </summary> | ||
| [JsonProperty("controls")] | ||
| public IEnumerable<Register> Controls { get; set; } = new List<Register>(); | ||
|
|
||
| /// <summary> | ||
| /// List of target registers. | ||
| /// </summary> | ||
| [JsonProperty("targets")] | ||
| public IEnumerable<Register> Targets { get; set; } = new List<Register>(); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| { | ||
| /// <summary> | ||
| /// Traces through the operations in a given execution path of a Q# program by hooking on | ||
| /// to a simulator via the event listeners <see cref="OnOperationStartHandler"/> and | ||
| /// <see cref="OnOperationEndHandler"/>, and generates the corresponding <see cref="ExecutionPath"/>. | ||
| /// </summary> | ||
| public class ExecutionPathTracer | ||
| { | ||
| private int currentDepth = 0; | ||
| private int renderDepth; | ||
| private IDictionary<int, QubitRegister> qubitRegisters = new Dictionary<int, QubitRegister>(); | ||
| private IDictionary<int, List<ClassicalRegister>> classicalRegisters = new Dictionary<int, List<ClassicalRegister>>(); | ||
| private List<Operation> operations = new List<Operation>(); | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="ExecutionPathTracer"/> class with the depth to render operations at. | ||
| /// </summary> | ||
| /// <param name="depth"> | ||
| /// The depth at which to render operations. | ||
| /// </param> | ||
| public ExecutionPathTracer(int depth = 1) => this.renderDepth = depth + 1; | ||
theRoughCode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// Returns the generated <see cref="ExecutionPath"/>. | ||
| /// </summary> | ||
| 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 | ||
| ); | ||
|
|
||
| /// <summary> | ||
| /// Provides the event listener to listen to | ||
| /// <see cref="Microsoft.Quantum.Simulation.Common.SimulatorBase"/>'s | ||
| /// <c>OnOperationStart</c> event. | ||
| /// </summary> | ||
| 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); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Provides the event listener to listen to | ||
| /// <see cref="Microsoft.Quantum.Simulation.Common.SimulatorBase"/>'s | ||
| /// <c>OnOperationEnd</c> event. | ||
| /// </summary> | ||
| public void OnOperationEndHandler(ICallable operation, IApplyData result) => this.currentDepth--; | ||
|
|
||
| /// <summary> | ||
| /// Retrieves the <see cref="QubitRegister"/> associated with the given <see cref="Qubit"/> or create a new | ||
| /// one if it doesn't exist. | ||
theRoughCode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// </summary> | ||
| private QubitRegister GetQubitRegister(Qubit qubit) => | ||
| this.qubitRegisters.GetOrCreate(qubit.Id, new QubitRegister(qubit.Id)); | ||
|
|
||
| private List<QubitRegister> GetQubitRegisters(IEnumerable<Qubit> qubits) => | ||
| qubits.Select(this.GetQubitRegister).ToList(); | ||
|
|
||
| /// <summary> | ||
| /// Creates a new <see cref="ClassicalRegister"/> and associate it with the given <see cref="Qubit"/>. | ||
| /// </summary> | ||
| private ClassicalRegister CreateClassicalRegister(Qubit measureQubit) | ||
theRoughCode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| 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; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Retrieves the most recent <see cref="ClassicalRegister"/> associated with the given <see cref="Qubit"/>. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// Currently not used as this is intended for classically-controlled operations. | ||
| /// </remarks> | ||
| 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]; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Parse <see cref="RuntimeMetadata"/> into its corresponding <see cref="Operation"/>. | ||
| /// </summary> | ||
| 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 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: this will be addressed in a separate PR so as not to clutter this one. |
||
| op.Gate = "measure"; | ||
| op.Controls = op.Targets; | ||
| op.Targets = new List<Register>() { clsReg }; | ||
| } | ||
|
|
||
| return op; | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| { | ||
| /// <summary> | ||
| /// Extension methods to be used with and by <see cref="ExecutionPathTracer">. | ||
| /// </summary> | ||
| public static class Extensions | ||
| { | ||
| /// <summary> | ||
| /// Attaches <see cref="ExecutionPathTracer"> event listeners to the simulator to generate | ||
| /// the <see cref="ExecutionPath"> of the operation performed by the simulator. | ||
| /// </summary> | ||
| public static T WithExecutionPathTracer<T>(this T sim, ExecutionPathTracer tracer) | ||
| where T : SimulatorBase | ||
| { | ||
| sim.OnOperationStart += tracer.OnOperationStartHandler; | ||
| sim.OnOperationEnd += tracer.OnOperationEndHandler; | ||
| return sim; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the value associated with the specified key and creates a new entry with the <c>defaultVal</c> if | ||
| /// the key doesn't exist. | ||
| /// </summary> | ||
| public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultVal) | ||
| { | ||
| TValue val; | ||
| if (!dict.TryGetValue(key, out val)) | ||
| { | ||
| val = defaultVal; | ||
| dict.Add(key, val); | ||
| } | ||
| return val; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the value associated with the specified key and creates a new entry of the default type if | ||
| /// the key doesn't exist. | ||
| /// </summary> | ||
| public static TValue GetOrCreate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) | ||
| where TValue : new() => dict.GetOrCreate(key, new TValue()); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.