Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,658 changes: 1,529 additions & 129 deletions documentation/examples/experimental-simulators-from-python.ipynb

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions documentation/experimental-simulators.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ The experimental simulators are not yet supported by:
- Q# standalone command-line programs
- QIR-based executables

## Known issues and limitations

As this feature is currently under development, there are still a number of limitations and missing capabilities.

- Continuous-time rotations (e.g.: `Rx`, `Ry`, `Rz`, and `Exp`) are not yet supported.
- Fractional rotations (e.g.: `R1Frac`, `ExpFrac`) are not yet supported.
- The `Controlled Y` operation with more than one control qubit is not yet supported.
- The `Controlled T` operation is not yet supported.
- Joint measurement is not yet supported.
- In some cases, qubits may need to be manually `Reset` before releasing, even if they have been measured.

Some limitations are inherent to open systems simulation, and may not ever be supported:

- Assertions (e.g.: `AssertMeasurement` and `AssertMeasurementProbability`) are not supported, as these assertions may fail for correct code in the presence of noise. These assertions are no-ops on the experimental simulators.

## Using Experimental Simulators from Python

> ### **ⓘ** TIP
Expand All @@ -34,6 +49,3 @@ After calling `enable_noisy_simulation()`, Q# operations imported into Python wi
By default, `.simulate_noise()` will assume an ideal error model (that is, no noise). To configure a particular error model, use the `qsharp.experimental.get_noise_model` and `qsharp.experimental.set_noise_model` functions to get and set the current noise model for the experimental simulators. Each error model is represented as a dictionary from intrinsic operation names to objects representing the errors in those intrinsic operations.

For open systems simulation, error channels can be represented by [QuTiP](https://qutip.org/) `Qobj` objects encoding superoperators.

> **Known limitation**: Currently, error channels for stabilizer simulation must be specified manually by their JSON serialization.

11 changes: 11 additions & 0 deletions src/Simulation/Native/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@ foo*
CMakeFiles/
CMakeCache.txt
*.so

# Ignore build artifacts...
win10
# ...except for vcomp140, which isn't actually a build
# artifact, but provides the Visual C/C++ OpenMP runtime
# needed by the full-state simulator.
#
# Making sure that this file is in the repo will make
# sure it ends up in our final NuGet packages, as needed
# for the full-state simulator to work correctly.
!win10/vcomp140.dll
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// # Design notes
//
// In testing the open systems simulator, we can't use the same approach used
// in testing other simulators. In particular, AssertMeasurement and
// AssertMeasurementProbability are no-ops on experimental simulators. Thus,
// we need to be a bit more indirect.
//
// Moreover, not all decompositions are supported yet
// (see documentation/experimental-simulators.md), such that we need to avoid
// unsupported cases.
//
// In this file, we list a bunch of operations that are unlikely to work
// correctly in the presence of decomposition bugs. This is not a guarantee,
// as we may have in the case of testing Choi–Jamilkowski states with
// assertions, but it should help build confidence in experimental simulator
// decompositions.
//
// In the future, consolidating these decompositions with those used in other
// targeting packages will allow using assertions on the full-state simulator
// to help build confidence in shared decompositions, further improving test
// coverage.

namespace Microsoft.Quantum.Experimental.Tests {
open Microsoft.Quantum.Intrinsic;
open Microsoft.Quantum.Diagnostics;

internal function Fact(expected : Bool, message : String) : Unit {
if not expected {
fail $"Fact was false: {message}";
}
}

internal operation MX(target : Qubit) : Result {
return Measure([PauliX], [target]);
}

@Test("Microsoft.Quantum.Experimental.OpenSystemsSimulator")
operation CheckBellBasisParitiesWithSingleQubitMeasurements() : Unit {
use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

Fact(M(left) == M(right), "Z parity in 00 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

Fact(MX(left) == MX(right), "X parity in 00 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

X(left);

Fact(M(left) != M(right), "Z parity in 10 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

X(left);

Fact(MX(left) == MX(right), "X parity in 10 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

Z(left);

Fact(M(left) == M(right), "Z parity in 01 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

Z(left);

Fact(MX(left) != MX(right), "X parity in 01 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

X(left);
Z(left);

Fact(M(left) != M(right), "Z parity in 11 case was wrong.");
ResetAll([left, right]);
}

use (left, right) = (Qubit(), Qubit()) {
H(left);
CNOT(left, right);

X(left);
Z(left);

Fact(MX(left) != MX(right), "X parity in 11 case was wrong.");
ResetAll([left, right]);
}
}

internal function Xor(a : Bool, b : Bool) : Bool {
return (a or b) and ((not a) or (not b));
}

@Test("Microsoft.Quantum.Experimental.OpenSystemsSimulator")
@Test("QuantumSimulator") // validate against full-state simulator.
operation CheckToffoliOnComputationalBasisStates() : Unit {
for in0 in [false, true] {
for in1 in [false, true] {
for output in [false, true] {
for useCcz in [false, true] {
use qs = Qubit[3];
if in0 { X(qs[0]); }
if in1 { X(qs[1]); }
if output { X(qs[2]); }

let expectedOut = Xor(output, in0 and in1);

if useCcz {
within {
H(qs[2]);
} apply {
Controlled Z([qs[0], qs[1]], qs[2]);
}
} else {
Controlled X([qs[0], qs[1]], qs[2]);
}

let results = [M(qs[0]), M(qs[1]), M(qs[2])];
let expected = [in0 ? One | Zero, in1 ? One | Zero, expectedOut ? One | Zero];

Fact(results[0] == expected[0], $"in0 was incorrect in case: {in0} {in1} {output}. Got {results[0]}, expected {expected[0]}.");
Fact(results[1] == expected[1], $"in1 was incorrect in case: {in0} {in1} {output}. Got {results[1]}, expected {expected[1]}.");
Fact(results[2] == expected[2], $"expected was incorrect in case: {in0} {in1} {output}. Got {results[2]}, expected {expected[2]}.");

ResetAll(qs);
}
}
}
}
}

@Test("Microsoft.Quantum.Experimental.OpenSystemsSimulator")
@Test("QuantumSimulator") // validate against full-state simulator.
operation CheckXHSZSHIsNoOp() : Unit {
use q = Qubit();

X(q);
within {
H(q);
S(q);
} apply {
Z(q);
}

Fact(M(q) == Zero, "XHSZSH was not a no-op.");
}

@Test("Microsoft.Quantum.Experimental.OpenSystemsSimulator")
@Test("QuantumSimulator") // validate against full-state simulator.
operation CheckControlledHWorks() : Unit {
use control = Qubit();
use target = Qubit();


Controlled H([control], target);
within {
X(control);
} apply {
Controlled H([control], target);
}
H(target);

Fact(M(control) == Zero, "Controlled H did not work correctly.");
Fact(M(target) == Zero, "Controlled H did not work correctly.");

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Linq;
using Microsoft.Quantum.Simulation.Core;
using Microsoft.Quantum.Simulation.Common;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Quantum.Simulation.Simulators.Exceptions;
using Microsoft.Quantum.Intrinsic.Interfaces;
using System.Collections.Generic;
using System.Diagnostics;
using Newtonsoft.Json.Linq;

namespace Microsoft.Quantum.Experimental
{
public partial class OpenSystemsSimulator
{
// These gates are not yet supported, pending a design for how to extend
// noise models to continuous-time gates (that is, those parameterized
// by real numbers, such as angles).

void IIntrinsicExp.Body(IQArray<Pauli> paulis, double angle, IQArray<Qubit> targets)
{
throw new NotImplementedException();
}

void IIntrinsicExp.AdjointBody(IQArray<Pauli> paulis, double angle, IQArray<Qubit> targets)
{
throw new NotImplementedException();
}

void IIntrinsicExp.ControlledBody(IQArray<Qubit> controls, IQArray<Pauli> paulis, double angle, IQArray<Qubit> targets)
{
throw new NotImplementedException();
}

void IIntrinsicExp.ControlledAdjointBody(IQArray<Qubit> controls, IQArray<Pauli> paulis, double angle, IQArray<Qubit> targets)
{
throw new NotImplementedException();
}
void IIntrinsicR.Body(Pauli pauli, double angle, Qubit target)
{
if (pauli == Pauli.PauliI)
{
// Don't apply global phases on uncontrolled operations.
return;
}
throw new NotImplementedException("Arbitrary rotation with noise is not yet supported.");
}

void IIntrinsicR.AdjointBody(Pauli pauli, double angle, Qubit target)
{
(this as IIntrinsicR).Body(pauli, -angle, target);
}

void IIntrinsicR.ControlledBody(IQArray<Qubit> controls, Pauli pauli, double angle, Qubit target)
{
if (controls is { Count: 0 })
{
(this as IIntrinsicR).Body(pauli, angle, target);
}
else
{
throw new NotImplementedException("Arbitrary controlled rotation with noise is not yet supported.");
}
}

void IIntrinsicR.ControlledAdjointBody(IQArray<Qubit> controls, Pauli pauli, double angle, Qubit target)
{
(this as IIntrinsicR).ControlledBody(controls, pauli, -angle, target);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// NB: Copied from Utils.qs.
namespace Microsoft.Quantum.Experimental.Decompositions {
open Microsoft.Quantum.Experimental.Native as Native;

/// Given a multiply-controlled operation that requires k controls
/// applies it using ceiling(k/2) controls and using floor(k/2) temporary qubits
operation ApplyWithLessControlsA<'T> (op : ((Qubit[],'T) => Unit is Adj), (controls : Qubit[], arg : 'T)) : Unit is Adj {
let numControls = Length(controls);
let numControlPairs = numControls / 2;
use temps = Qubit[numControlPairs] {
within {
for numPair in 0 .. numControlPairs - 1 { // constant depth
PhaseCCX(controls[2 * numPair], controls[2 * numPair + 1], temps[numPair]);
}
}
apply {
let newControls = numControls % 2 == 0 ? temps | temps + [controls[numControls - 1]];
op(newControls, arg);
}
}
}

operation PhaseCCX (control1 : Qubit, control2 : Qubit, target : Qubit) : Unit is Adj {
// https://arxiv.org/pdf/1210.0974.pdf#page=2
Native.H(target);
Native.CNOT(target,control1);
Native.CNOT(control1,control2);
Native.T(control2);
Adjoint Native.T(control1);
Native.T(target);
Native.CNOT(target,control1);
Native.CNOT(control1,control2);
Adjoint Native.T(control2);
Native.CNOT(target,control2);
Native.H(target);
}
}

This file was deleted.

Loading