/// <summary> /// Simulates an operation given a string with its name and a JSON /// encoding of its arguments. /// </summary> public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); var name = inputParameters.DecodeParameter <string>(ParameterNameOperationName); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } var maxNQubits = 0L; using var qsim = new QuantumSimulator() .WithJupyterDisplay(channel, ConfigurationSource) .WithStackTraceDisplay(channel); qsim.OnDisplayableDiagnostic += channel.Display; qsim.AfterAllocateQubits += (args) => { maxNQubits = System.Math.Max(qsim.QubitManager.AllocatedQubitsCount, maxNQubits); }; var stopwatch = Stopwatch.StartNew(); var value = await symbol.Operation.RunAsync(qsim, inputParameters); stopwatch.Stop(); var result = value.ToExecutionResult(); (Monitor as PerformanceMonitor)?.ReportSimulatorPerformance(new SimulatorPerformanceArgs( simulatorName: qsim.GetType().FullName, nQubits: (int)maxNQubits, duration: stopwatch.Elapsed )); return(result); }
/// <summary> /// Outputs a visualization of a runtime execution path of an operation given /// a string with its name and a JSON encoding of its arguments. /// </summary> public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { // Parse input parameters var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); var name = inputParameters.DecodeParameter <string>(ParameterNameOperationName); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } if (!inputParameters.TryDecodeParameter <int>( ParameterNameDepth, out var depth, defaultValue: this.ConfigurationSource.TraceVisualizationDefaultDepth )) { channel.Stderr($"Expected {ParameterNameDepth} to be an integer, but got {inputParameters[ParameterNameDepth]}."); return(ExecuteStatus.Error.ToExecutionResult()); } if (depth <= 0) { channel.Stderr($"Expected {ParameterNameDepth} to be >= 1, but got {depth}."); return(ExecuteStatus.Error.ToExecutionResult()); } var tracer = new ExecutionPathTracer.ExecutionPathTracer(); // Simulate operation and attach `ExecutionPathTracer` to trace out operations performed // in its execution path using var qsim = new QuantumSimulator() .WithExecutionPathTracer(tracer); var value = await symbol.Operation.RunAsync(qsim, inputParameters); var divId = $"execution-path-container-{Guid.NewGuid()}"; channel.DisplayUpdatable(new DisplayableHtmlElement($"<div id='{divId}' />")); // Render the `ExecutionPath` traced out by the `ExecutionPathTracer` tracer.RenderExecutionPath(channel, divId, depth, this.ConfigurationSource.TraceVisualizationStyle); return(ExecuteStatus.Ok.ToExecutionResult()); }
/// <summary> /// Simulates an operation given a string with its name and a JSON /// encoding of its arguments. /// </summary> public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { var(name, args) = ParseInput(input); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } using var qsim = new QuantumSimulator() .WithJupyterDisplay(channel, ConfigurationSource) .WithStackTraceDisplay(channel); var value = await symbol.Operation.RunAsync(qsim, args); return(value.ToExecutionResult()); }
/// <summary> /// Simulates an operation given a string with its name and a JSON /// encoding of its arguments. /// </summary> public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); var name = inputParameters.DecodeParameter <string>(ParameterNameOperationName); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } using var qsim = new QuantumSimulator() .WithJupyterDisplay(channel, ConfigurationSource) .WithStackTraceDisplay(channel); var value = await symbol.Operation.RunAsync(qsim, inputParameters); return(value.ToExecutionResult()); }
public async Task <ExecutionResult> RunAsync(string input, IChannel channel, CancellationToken?token = null) { var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); var name = inputParameters.DecodeParameter <string>(ParameterNameOperationName); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } var session = Guid.NewGuid(); var debugSessionDivId = session.ToString(); lock (SessionAdvanceEvents) { SessionAdvanceEvents[session] = new ManualResetEvent(true); } // Set up the simulator and execution path tracer var tracer = new ExecutionPathTracer.ExecutionPathTracer(); using var qsim = new QuantumSimulator() .WithExecutionPathTracer(tracer); // Render the placeholder for the debug UX. channel.Stdout($"Starting debug session for {name}..."); channel.Display(new DisplayableHtmlElement($@"<div id='{debugSessionDivId}' />")); channel.SendIoPubMessage( new Message { Header = new MessageHeader { MessageType = "iqsharp_debug_sessionstart" }, Content = new DebugSessionContent { DivId = debugSessionDivId, DebugSession = session.ToString(), } } ); // Render the placeholder for the execution path. var executionPathDivId = $"execution-path-container-{Guid.NewGuid()}"; channel.Display(new DisplayableHtmlElement($"<div id='{executionPathDivId}' />")); // Set up the OnOperationStart handler. qsim.OnOperationStart += (callable, args) => { if (!(token ?? CancellationTokenSource.Token).IsCancellationRequested) { var allocatedQubitsCount = (int)(qsim.QubitManager?.AllocatedQubitsCount ?? 0); if (allocatedQubitsCount == 0) { return; } // Tell the IOPub channel that we're starting a new operation. channel.SendIoPubMessage( new Message { Header = new MessageHeader { MessageType = "iqsharp_debug_opstart" }, Content = new DebugStatusContent { DebugSession = session.ToString(), State = new DisplayableState { QubitIds = qsim.QubitIds.Select(q => (int)q), NQubits = allocatedQubitsCount, Amplitudes = new DebugStateDumper(qsim).GetAmplitudes(), DivId = debugSessionDivId } } } ); } WaitForAdvance(session, token).Wait(); }; qsim.OnOperationEnd += (callable, args) => { if (!(token ?? CancellationTokenSource.Token).IsCancellationRequested) { // Render the `ExecutionPath` traced out by the `ExecutionPathTracer` tracer.RenderExecutionPath( channel, executionPathDivId, renderDepth: 1, this.ConfigurationSource.TraceVisualizationStyle); } }; try { // Simulate the operation. var value = await Task.Run(() => symbol.Operation.RunAsync(qsim, inputParameters), token ?? CancellationTokenSource.Token); return(value.ToExecutionResult()); } finally { // Report completion. channel.Stdout($"Finished debug session for {name}."); channel.SendIoPubMessage( new Message { Header = new MessageHeader { MessageType = "iqsharp_debug_sessionend" }, Content = new DebugSessionContent { DivId = debugSessionDivId, DebugSession = session.ToString(), } } ); } }
/// <summary> /// Outputs a visualization of a runtime execution path of an operation given /// a string with its name and a JSON encoding of its arguments. /// </summary> public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { // Parse input parameters var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName); var name = inputParameters.DecodeParameter <string>(ParameterNameOperationName); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } var depth = inputParameters.DecodeParameter <int>( ParameterNameDepth, defaultValue: this.ConfigurationSource.TraceVisualizationDefaultDepth ); if (depth <= 0) { throw new ArgumentOutOfRangeException($"Invalid depth: {depth}. Must be >= 1."); } var tracer = new ExecutionPathTracer.ExecutionPathTracer(); // Simulate operation and attach `ExecutionPathTracer` to trace out operations performed // in its execution path using var qsim = new QuantumSimulator() .WithJupyterDisplay(channel, ConfigurationSource) .WithStackTraceDisplay(channel) .WithExecutionPathTracer(tracer); var value = await symbol.Operation.RunAsync(qsim, inputParameters); // Retrieve the `ExecutionPath` traced out by the `ExecutionPathTracer` var executionPath = tracer.GetExecutionPath(); // Convert executionPath to JToken for serialization var executionPathJToken = JToken.FromObject(executionPath, new JsonSerializer() { NullValueHandling = NullValueHandling.Ignore }); // Render empty div with unique ID as cell output var divId = $"execution-path-container-{Guid.NewGuid().ToString()}"; var content = new ExecutionPathVisualizerContent( executionPathJToken, divId, depth, this.ConfigurationSource.TraceVisualizationStyle ); channel.DisplayUpdatable(new DisplayableHtmlElement($"<div id='{divId}' />")); // Send execution path to JavaScript via iopub for rendering channel.SendIoPubMessage( new Message { Header = new MessageHeader { MessageType = "render_execution_path" }, Content = content, } ); return(ExecuteStatus.Ok.ToExecutionResult()); }