diff --git a/src/Jupyter/Magic/AbstractNativeSimulateMagic.cs b/src/Jupyter/Magic/AbstractNativeSimulateMagic.cs
new file mode 100644
index 0000000000..cee7d6c8d0
--- /dev/null
+++ b/src/Jupyter/Magic/AbstractNativeSimulateMagic.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ public abstract class AbstractNativeSimulateMagic : AbstractMagic
+ {
+ private const string ParameterNameOperationName = "__operationName__";
+ private readonly IPerformanceMonitor Monitor;
+
+ ///
+ /// Constructs a new magic command given a resolver used to find
+ /// operations and functions, and a configuration source used to set
+ /// configuration options.
+ ///
+ public AbstractNativeSimulateMagic(string keyword, Documentation docs, ISymbolResolver resolver,
+ IConfigurationSource configurationSource, IPerformanceMonitor monitor,
+ ILogger logger)
+ : base(keyword, docs, logger)
+ {
+ this.SymbolResolver = resolver;
+ this.ConfigurationSource = configurationSource;
+ this.Monitor = monitor;
+ }
+
+ ///
+ /// The symbol resolver used by this magic command to find
+ /// operations or functions to be simulated.
+ ///
+ public ISymbolResolver SymbolResolver { get; }
+
+ ///
+ /// The configuration source used by this magic command to control
+ /// simulation options (e.g.: dump formatting options).
+ ///
+ public IConfigurationSource ConfigurationSource { get; }
+
+ ///
+ public override ExecutionResult Run(string input, IChannel channel) =>
+ RunAsync(input, channel).Result;
+
+ internal abstract CommonNativeSimulator CreateNativeSimulator();
+
+ ///
+ /// Simulates an operation given a string with its name and a JSON
+ /// encoding of its arguments.
+ ///
+ public async Task RunAsync(string input, IChannel channel)
+ {
+ var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName);
+
+ var name = inputParameters.DecodeParameter(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;
+ }
+ }
+}
diff --git a/src/Jupyter/Magic/Simulate.cs b/src/Jupyter/Magic/Simulate.cs
index 3e9f9e5bf6..b43fef5ce8 100644
--- a/src/Jupyter/Magic/Simulate.cs
+++ b/src/Jupyter/Magic/Simulate.cs
@@ -16,11 +16,8 @@ namespace Microsoft.Quantum.IQSharp.Jupyter
/// A magic command that can be used to simulate operations and functions
/// on a full-state quantum simulator.
///
- public class SimulateMagic : AbstractMagic
+ public class SimulateMagic : AbstractNativeSimulateMagic
{
- private const string ParameterNameOperationName = "__operationName__";
- private readonly IPerformanceMonitor Monitor;
-
///
/// Constructs a new magic command given a resolver used to find
/// operations and functions, and a configuration source used to set
@@ -61,96 +58,10 @@ or function name that has been defined either in the notebook or in a Q# file in
```
".Dedent(),
}
- }, logger)
+ }, resolver, configurationSource, monitor, logger)
{
- this.SymbolResolver = resolver;
- this.ConfigurationSource = configurationSource;
- this.Monitor = monitor;
}
- ///
- /// The symbol resolver used by this magic command to find
- /// operations or functions to be simulated.
- ///
- public ISymbolResolver SymbolResolver { get; }
-
- ///
- /// The configuration source used by this magic command to control
- /// simulation options (e.g.: dump formatting options).
- ///
- public IConfigurationSource ConfigurationSource { get; }
-
- ///
- public override ExecutionResult Run(string input, IChannel channel) =>
- RunAsync(input, channel).Result;
-
- ///
- /// Simulates an operation given a string with its name and a JSON
- /// encoding of its arguments.
- ///
- public async Task RunAsync(string input, IChannel channel)
- {
- var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameOperationName);
-
- var name = inputParameters.DecodeParameter(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()
- .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;
- }
+ internal override CommonNativeSimulator CreateNativeSimulator() => new QuantumSimulator();
}
}
diff --git a/src/Jupyter/Magic/SimulateSparse.cs b/src/Jupyter/Magic/SimulateSparse.cs
new file mode 100644
index 0000000000..572510753a
--- /dev/null
+++ b/src/Jupyter/Magic/SimulateSparse.cs
@@ -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
+{
+ ///
+ /// A magic command that can be used to simulate operations and functions
+ /// on a sparse simulator.
+ ///
+ public class SimulateSparseMagic : AbstractNativeSimulateMagic
+ {
+ ///
+ /// Constructs a new magic command given a resolver used to find
+ /// operations and functions, and a configuration source used to set
+ /// configuration options.
+ ///
+ public SimulateSparseMagic(ISymbolResolver resolver, IConfigurationSource configurationSource, IPerformanceMonitor monitor, ILogger 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[]:
+ ```
+ ".Dedent(),
+ @"
+ Simulate a Q# operation defined as `operation MyOperation(a : Int, b : Int) : Result`:
+ ```
+ In []: %simulate_sparse MyOperation a=5 b=10
+ Out[]:
+ ```
+ ".Dedent(),
+ }
+ }, resolver, configurationSource, monitor, logger)
+ {
+ }
+
+ internal override CommonNativeSimulator CreateNativeSimulator() => new SparseSimulator();
+ }
+}
diff --git a/src/Python/qsharp-core/qsharp/clients/iqsharp.py b/src/Python/qsharp-core/qsharp/clients/iqsharp.py
index 173b2f1b39..465b8718a9 100644
--- a/src/Python/qsharp-core/qsharp/clients/iqsharp.py
+++ b/src/Python/qsharp-core/qsharp/clients/iqsharp.py
@@ -173,6 +173,10 @@ def simulate(self, op, **kwargs) -> Any:
kwargs.setdefault('_timeout_', None)
return self._execute_callable_magic('simulate', op, **kwargs)
+ def simulate_sparse(self, op, **kwargs) -> Any:
+ kwargs.setdefault('_timeout_', None)
+ return self._execute_callable_magic('simulate_sparse', op, **kwargs)
+
def toffoli_simulate(self, op, **kwargs) -> Any:
kwargs.setdefault('_timeout_', None)
return self._execute_callable_magic('toffoli', op, **kwargs)
diff --git a/src/Python/qsharp-core/qsharp/loader.py b/src/Python/qsharp-core/qsharp/loader.py
index 13a71d4713..f136cbbdd2 100644
--- a/src/Python/qsharp-core/qsharp/loader.py
+++ b/src/Python/qsharp-core/qsharp/loader.py
@@ -90,6 +90,13 @@ def simulate(self, **kwargs) -> Any:
"""
return qsharp.client.simulate(self, **kwargs)
+ def simulate_sparse(self, **kwargs) -> Any:
+ """
+ Executes this function or operation on the sparse simulator, returning
+ its output as a Python object.
+ """
+ return qsharp.client.simulate_sparse(self, **kwargs)
+
def toffoli_simulate(self, **kwargs) -> Any:
"""
Executes this function or operation on the ToffoliSimulator target
diff --git a/src/Tests/IQsharpEngineTests.cs b/src/Tests/IQsharpEngineTests.cs
index dc8843a809..fac83224ab 100644
--- a/src/Tests/IQsharpEngineTests.cs
+++ b/src/Tests/IQsharpEngineTests.cs
@@ -183,7 +183,10 @@ public async Task CompleteMagic() =>
await Assert.That
.UsingEngine()
.Input("%sim", 3)
- .CompletesTo("%simulate")
+ .CompletesTo(
+ "%simulate",
+ "%simulate_sparse"
+ )
.Input("%experimental.", 14)
.CompletesTo(
"%experimental.build_info",