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 56
Add magic command and QSharpCallable method. #587
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
eaabbd9
Adapting to the change in QuantumSimulator Dump.
kuzminrobin 772749b
Adapting to Dump change in QuantumSimulator.
kuzminrobin 8b6d622
Added string reverse of DisplayableState index.
kuzminrobin 1d20e6d
Switched to BigInteger index.
kuzminrobin d8bf3b6
Renamed ParseUnsignedBitString() to ParseUnsignedLEBitString().
kuzminrobin 803de02
Minor clean-up.
kuzminrobin e006154
Minor refactoring.
kuzminrobin e0028ab
Updated the .Simulators package version.
kuzminrobin 2353ebf
Updated teh packages version.
kuzminrobin 5d3a894
Add support for sparse simulator.
cgranade ab7b91f
Update src/Jupyter/Magic/AbstractNativeSimulateMagic.cs
7d2036e
Adapt completemagic test.
cgranade cc4a1ac
Merge branch 'main' into cgranade/sparse-magic
bettinaheim 127f37c
Minor typo fix.
kuzminrobin 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,127 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Jupyter.Core; | ||
| using Microsoft.Quantum.IQSharp.Common; | ||
| using Microsoft.Quantum.Simulation.Core; | ||
| using Microsoft.Quantum.Simulation.Simulators; | ||
|
|
||
| namespace Microsoft.Quantum.IQSharp.Jupyter | ||
| { | ||
| /// <summary> | ||
| /// Abstract class for magic commands that can be used to simulate | ||
| /// operations and functions on a full-state quantum simulator, using | ||
| /// a common C API. | ||
| /// </summary> | ||
| public abstract class AbstractNativeSimulateMagic : AbstractMagic | ||
| { | ||
| private const string ParameterNameOperationName = "__operationName__"; | ||
| private readonly IPerformanceMonitor Monitor; | ||
|
|
||
| /// <summary> | ||
| /// Constructs a new magic command given a resolver used to find | ||
| /// operations and functions, and a configuration source used to set | ||
| /// configuration options. | ||
| /// </summary> | ||
| public AbstractNativeSimulateMagic(string keyword, Documentation docs, ISymbolResolver resolver, | ||
| IConfigurationSource configurationSource, IPerformanceMonitor monitor, | ||
| ILogger<AbstractNativeSimulateMagic> logger) | ||
| : base(keyword, docs, logger) | ||
| { | ||
| this.SymbolResolver = resolver; | ||
| this.ConfigurationSource = configurationSource; | ||
| this.Monitor = monitor; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The symbol resolver used by this magic command to find | ||
| /// operations or functions to be simulated. | ||
| /// </summary> | ||
| public ISymbolResolver SymbolResolver { get; } | ||
|
|
||
| /// <summary> | ||
| /// The configuration source used by this magic command to control | ||
| /// simulation options (e.g.: dump formatting options). | ||
| /// </summary> | ||
| public IConfigurationSource ConfigurationSource { get; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override ExecutionResult Run(string input, IChannel channel) => | ||
| RunAsync(input, channel).Result; | ||
|
|
||
| internal abstract CommonNativeSimulator CreateNativeSimulator(); | ||
|
|
||
| /// <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 = CreateNativeSimulator() | ||
| .WithStackTraceDisplay(channel); | ||
|
|
||
| qsim.DisableLogToConsole(); | ||
| qsim.OnLog += channel.Stdout; | ||
|
|
||
| qsim.OnDisplayableDiagnostic += (displayable) => | ||
| { | ||
| if (displayable is CommonNativeSimulator.DisplayableState state && ConfigurationSource.MeasurementDisplayHistogram) | ||
| { | ||
| // Make sure to display the state first so that it's there for the client-side | ||
| // JavaScript to pick up. | ||
| var id = $"{System.Guid.NewGuid()}"; | ||
| channel.Display(new DisplayableStateWithId | ||
| { | ||
| Amplitudes = state.Amplitudes, | ||
| NQubits = state.NQubits, | ||
| QubitIds = state.QubitIds, | ||
| Id = id | ||
| }); | ||
|
|
||
| // Tell the client to add a histogram using chart.js. | ||
| var commsRouter = channel.GetCommsRouter(); | ||
| Debug.Assert(commsRouter != null, "Histogram display requires comms router."); | ||
| commsRouter.OpenSession( | ||
| "iqsharp_state_dump", | ||
| new MeasurementHistogramContent() | ||
| { | ||
| State = state, | ||
| Id = id | ||
| } | ||
| ).Wait(); | ||
| } | ||
| else | ||
| { | ||
| channel.Display(displayable); | ||
| } | ||
| }; | ||
|
|
||
| qsim.AfterAllocateQubits += (args) => | ||
| { | ||
| maxNQubits = System.Math.Max(qsim.QubitManager?.AllocatedQubitsCount ?? 0, 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; | ||
| } | ||
| } | ||
| } |
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
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,65 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.Threading.Tasks; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Jupyter.Core; | ||
| using Microsoft.Quantum.IQSharp.Common; | ||
| using Microsoft.Quantum.Simulation.Core; | ||
| using Microsoft.Quantum.Simulation.Simulators; | ||
|
|
||
| namespace Microsoft.Quantum.IQSharp.Jupyter | ||
| { | ||
| /// <summary> | ||
| /// A magic command that can be used to simulate operations and functions | ||
| /// on a sparse simulator. | ||
| /// </summary> | ||
| public class SimulateSparseMagic : AbstractNativeSimulateMagic | ||
| { | ||
| /// <summary> | ||
| /// Constructs a new magic command given a resolver used to find | ||
| /// operations and functions, and a configuration source used to set | ||
| /// configuration options. | ||
| /// </summary> | ||
| public SimulateSparseMagic(ISymbolResolver resolver, IConfigurationSource configurationSource, IPerformanceMonitor monitor, ILogger<SimulateSparseMagic> logger) : base( | ||
| "simulate_sparse", | ||
| new Microsoft.Jupyter.Core.Documentation | ||
| { | ||
| Summary = "Runs a given function or operation on the sparse simulator.", | ||
| Description = @" | ||
| This magic command allows executing a given function or operation on the sparse simulator, | ||
| which performs a sparse simulation of the given function or operation | ||
| and prints the resulting return value. | ||
|
|
||
| #### Required parameters | ||
|
|
||
| - Q# operation or function name. This must be the first parameter, and must be a valid Q# operation | ||
| or function name that has been defined either in the notebook or in a Q# file in the same folder. | ||
| - Arguments for the Q# operation or function must also be specified as `key=value` pairs. | ||
| ".Dedent(), | ||
| Examples = new [] | ||
| { | ||
| @" | ||
| Simulate a Q# operation defined as `operation MyOperation() : Result`: | ||
| ``` | ||
| In []: %simulate_sparse MyOperation | ||
| Out[]: <return value of the operation> | ||
| ``` | ||
| ".Dedent(), | ||
| @" | ||
| Simulate a Q# operation defined as `operation MyOperation(a : Int, b : Int) : Result`: | ||
| ``` | ||
| In []: %simulate_sparse MyOperation a=5 b=10 | ||
| Out[]: <return value of the operation> | ||
| ``` | ||
| ".Dedent(), | ||
| } | ||
| }, resolver, configurationSource, monitor, logger) | ||
| { | ||
| } | ||
|
|
||
| internal override CommonNativeSimulator CreateNativeSimulator() => new SparseSimulator(); | ||
| } | ||
| } |
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
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
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add a magic command simulate_fullstate that resolves to the quantum simulator? The simulate command for now can stay as it is, but it would be good to have the option to treat it as something that resolves to a default choice later on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not, but instead would want to find the right way to add a keyword argument to
.simulateitself for the simulator and remove all of the other method calls.For using Q# notebooks directly, we can use
--simulatoras a parameter name to disambiguate the simulator choice from inputs to the Q# entry point itself, but for Python we need to do something different to disambiguate. For example, we could considerdef simulate(self, op, __simulator=None, **kwargs)since the__prefix is reserved in Q# and cannot be listed as an entry point input. Using that, the full-state simulator would be usable asRunFoo.simulate("full-state", x=3)and the sparse simulator would be usable asRunFoo.simulate("sparse", x=3). That would also allow custom third-party simulators to be added more easily without modifying existing APIs, reducing the challenges run into by https://github.com/qsharp-community/chp-sim. That would also make it easier to add a new config settingqsharp.config['simulator.default']that users could use to work with default simulator preferences.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am open to how exactly the commands should look like. I believe the following points would be important:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In earlier runtime versions, individual simulators needed much more customization than is currently needed, such that this is much more plausible than before. In particular, much of the sparse simulator work resulted in a significant reduction of code volume in IQ# by removing the override that the
%simulatecommand used to need in order to provide visualizations for the full-state simulator.That said, even with the previous approach of a new command for each simulator, third-party simulators such as https://github.com/qsharp-community/chp-sim were able to use IQ#'s functionality for dynamic loading of new magic commands to add new simulators. For example, using the chp-sim package, a user could run
%package QSharpCommunity.Simulators.Chp, at which point IQ# automatically discovered the new simulator command, added it to documentation in the%lsmagiccommand, tab completion, and so forth. I want to make sure that as we consolidate simulator logic into a single command, and as we make it easier to enable third party simulators, we also maintain the current user experience, wherein dynamically loaded simulators are easily discoverable at runtime. Perhaps something like%simulate --list-availableto list currently known simulators?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to make a complete list for how all simulator related magic commands could look like? Also, I didn't fully realize that the functionality to discover available simulator was added. Given that, what is the reason for wanting to revise the current API further?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is, but only through having a proliferation of distinct magic commands. Consolidating the API into a single magic command with an argument for different simulators is much more maintainable and I'd argue usable as well. Deferring past this PR for now, in any case.