This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 919
/
Simulator.cs
102 lines (93 loc) · 4.13 KB
/
Simulator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
using Microsoft.Quantum.Simulation.QuantumProcessor;
using Microsoft.Quantum.Simulation.Common;
using Microsoft.Quantum.Simulation.Core;
namespace Microsoft.Quantum.Samples
{
// The ReversibleSimulator will be implemented based on
// `QuantumProcessorDispatcher`, which is constructed using a specialization
// `QuantumProcessorBase`. The specialization overrides methods to specify
// actions on intrinsic operations in the Q# code.
class ReversibleSimulatorProcessor : QuantumProcessorBase
{
// For simplicity, we are using a dictionary to map qubits to their
// current simulation value.
private IDictionary<Qubit, bool> simulationValues = new Dictionary<Qubit, bool>();
// This method is called whenever new qubits are allocated using a
// `using` statement in Q#. The newly allocated qubits are passed as
// an argument to the method.
public override void OnAllocateQubits(IQArray<Qubit> qubits)
{
// Each allocated qubit is inserted into the dictionary with an
// initial value of `false`.
foreach (var qubit in qubits)
{
simulationValues[qubit] = false;
}
}
// Whenever qubits are released, when leaving the scope of a `using`
// statement in Q#, this method is called with the qubits that are
// being released.
public override void OnReleaseQubits(IQArray<Qubit> qubits)
{
// Each released qubit is removed from the dictionary.
foreach (var qubit in qubits)
{
simulationValues.Remove(qubit);
}
}
// This method is called on a non-controlled `X` operation, applied to
// the qubit `qubit`.
public override void X(Qubit qubit)
{
// The simulation value of the qubit is inverted.
simulationValues[qubit] = !simulationValues[qubit];
}
// This helper method returns true, if and only if the simulation value
// of all qubits in the array `qubits` is true. It is used in the
// implementation of a controlled X operation.
private bool And(IQArray<Qubit> qubits)
{
foreach (var qubit in qubits)
{
if (!simulationValues[qubit])
{
return false;
}
}
return true;
}
// This method is called on a controlled `X` operation (incl. CNOT and
// CCNOT), with controls on `controls`, applied to the qubit `qubit.
public override void ControlledX(IQArray<Qubit> controls, Qubit qubit)
{
// The right-hand side evaluates to true, if and only if the
// simulation value of all control qubits is `true`. In that case
// the simulation value of the target qubit is inverted.
simulationValues[qubit] ^= And(controls);
}
// This method is called when the `Reset` operation is called in the Q#
// program. The qubit will still be available, in contrast to a
// released qubit.
public override void Reset(Qubit qubit)
{
// The simulation value is reset to the initial value `false`.
simulationValues[qubit] = false;
}
// When calling `M` on some qubit `qubit`, this method is called. The
// method returns an instance of type `Result`.
public override Result M(Qubit qubit) =>
// The simulation value is converted to a Q# result value: `true`
// corresponds to `One`, and `false` corresponds to `Zero`.
simulationValues[qubit].ToResult();
}
// The actual simulator is created by extending
// `QuantumProcessorDispatcher`, which is constructed using the
// `ReversibleSimulatorProcessor`.
public class ReversibleSimulator : QuantumProcessorDispatcher
{
public ReversibleSimulator() : base(new ReversibleSimulatorProcessor()) {}
}
}