|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Numerics; |
| 5 | +using Newtonsoft.Json; |
| 6 | +using Newtonsoft.Json.Converters; |
| 7 | + |
| 8 | +namespace Microsoft.Quantum.Simulation.Simulators |
| 9 | +{ |
| 10 | + public partial class CommonNativeSimulator |
| 11 | + { |
| 12 | + /// <summary> |
| 13 | + /// The convention to be used in labeling computational basis states |
| 14 | + /// given their representations as strings of classical bits. |
| 15 | + /// </summary> |
| 16 | + [JsonConverter(typeof(StringEnumConverter))] |
| 17 | + public enum BasisStateLabelingConvention |
| 18 | + { |
| 19 | + /// <summary> |
| 20 | + /// Label computational states directly by their bit strings. |
| 21 | + /// </summary> |
| 22 | + /// <example> |
| 23 | + /// Following this convention, the state |0⟩ ⊗ |1⟩ ⊗ |1⟩ is labeled |
| 24 | + /// by |011⟩. |
| 25 | + /// </example> |
| 26 | + Bitstring, |
| 27 | + |
| 28 | + /// <summary> |
| 29 | + /// Label computational states directly by interpreting their bit |
| 30 | + /// strings as little-endian encoded integers. |
| 31 | + /// </summary> |
| 32 | + /// <example> |
| 33 | + /// Following this convention, the state |0⟩ ⊗ |1⟩ ⊗ |1⟩ is labeled |
| 34 | + /// by |6⟩. |
| 35 | + /// </example> |
| 36 | + LittleEndian, |
| 37 | + |
| 38 | + /// <summary> |
| 39 | + /// Label computational states directly by interpreting their bit |
| 40 | + /// strings as big-endian encoded integers. |
| 41 | + /// </summary> |
| 42 | + /// <example> |
| 43 | + /// Following this convention, the state |0⟩ ⊗ |1⟩ ⊗ |1⟩ is labeled |
| 44 | + /// by |3⟩. |
| 45 | + /// </example> |
| 46 | + BigEndian |
| 47 | + } |
| 48 | + |
| 49 | + /// <summary> |
| 50 | + /// Represents a quantum state vector and all metadata needed to display |
| 51 | + /// that state vector. |
| 52 | + /// </summary> |
| 53 | + public class DisplayableState |
| 54 | + { |
| 55 | + private static readonly IComparer<string> ToIntComparer = |
| 56 | + Comparer<string>.Create((label1, label2) => |
| 57 | + Comparer<int>.Default.Compare( |
| 58 | + Int32.Parse(label1), Int32.Parse(label2) |
| 59 | + ) |
| 60 | + ); |
| 61 | + |
| 62 | + /// <summary> |
| 63 | + /// Metadata to be used when serializing to JSON, allowing code |
| 64 | + /// in other languages to determine what representation is used |
| 65 | + /// for this state. |
| 66 | + /// </summary> |
| 67 | + [JsonProperty("diagnostic_kind")] |
| 68 | + private string DiagnosticKind => "state-vector"; |
| 69 | + |
| 70 | + /// <summary> |
| 71 | + /// The indexes of each qubit on which this state is defined, or |
| 72 | + /// <c>null</c> if these indexes are not known. |
| 73 | + /// </summary> |
| 74 | + [JsonProperty("qubit_ids")] |
| 75 | + public IEnumerable<int>? QubitIds { get; set; } |
| 76 | + |
| 77 | + /// <summary> |
| 78 | + /// The number of qubits on which this state is defined. |
| 79 | + /// </summary> |
| 80 | + [JsonProperty("n_qubits")] |
| 81 | + public int NQubits { get; set; } |
| 82 | + |
| 83 | + /// <remarks> |
| 84 | + /// These amplitudes represent the computational basis states |
| 85 | + /// labeled in little-endian order, as per the behavior of |
| 86 | + /// <see cref="Microsoft.Quantum.Simulation.Simulators.CommonNativeSimulator.StateDumper.Dump" />. |
| 87 | + /// </remarks> |
| 88 | + [JsonProperty("amplitudes")] |
| 89 | + public IDictionary<int, Complex>? Amplitudes { get; set; } |
| 90 | + |
| 91 | + /// <summary> |
| 92 | + /// An enumerable source of the significant amplitudes of this state |
| 93 | + /// vector and their labels. |
| 94 | + /// </summary> |
| 95 | + /// <param name="convention"> |
| 96 | + /// The convention to be used in labeling each computational basis state. |
| 97 | + /// </param> |
| 98 | + /// <param name="truncateSmallAmplitudes"> |
| 99 | + /// Whether to truncate small amplitudes. |
| 100 | + /// </param> |
| 101 | + /// <param name="truncationThreshold"> |
| 102 | + /// If <paramref name="truncateSmallAmplitudes" /> is <c>true</c>, |
| 103 | + /// then amplitudes whose absolute value squared are below this |
| 104 | + /// threshold are suppressed. |
| 105 | + /// </param> |
| 106 | + public IEnumerable<(Complex, string)> SignificantAmplitudes( |
| 107 | + BasisStateLabelingConvention convention, |
| 108 | + bool truncateSmallAmplitudes, double truncationThreshold |
| 109 | + ) => |
| 110 | + ( |
| 111 | + truncateSmallAmplitudes |
| 112 | + ? Amplitudes |
| 113 | + .Where(item => |
| 114 | + System.Math.Pow(item.Value.Magnitude, 2.0) >= truncationThreshold |
| 115 | + ) |
| 116 | + : Amplitudes |
| 117 | + ) |
| 118 | + .Select( |
| 119 | + item => (item.Value, BasisStateLabel(convention, item.Key)) |
| 120 | + ) |
| 121 | + .OrderBy( |
| 122 | + item => item.Item2, |
| 123 | + // If a basis state label is numeric, we want to compare |
| 124 | + // numerically rather than lexographically. |
| 125 | + convention switch { |
| 126 | + BasisStateLabelingConvention.BigEndian => ToIntComparer, |
| 127 | + BasisStateLabelingConvention.LittleEndian => ToIntComparer, |
| 128 | + _ => Comparer<string>.Default |
| 129 | + } |
| 130 | + ); |
| 131 | + |
| 132 | + /// <summary> |
| 133 | + /// Using the given labeling convention, returns the label for a |
| 134 | + /// computational basis state described by its bit string as encoded |
| 135 | + /// into an integer index in the little-endian encoding. |
| 136 | + /// </summary> |
| 137 | + public string BasisStateLabel( |
| 138 | + BasisStateLabelingConvention convention, int index |
| 139 | + ) => convention switch |
| 140 | + { |
| 141 | + BasisStateLabelingConvention.Bitstring => |
| 142 | + String.Concat( |
| 143 | + System |
| 144 | + .Convert |
| 145 | + .ToString(index, 2) |
| 146 | + .PadLeft(NQubits, '0') |
| 147 | + .Reverse() |
| 148 | + ), |
| 149 | + BasisStateLabelingConvention.BigEndian => |
| 150 | + System.Convert.ToInt64( |
| 151 | + String.Concat( |
| 152 | + System.Convert.ToString(index, 2).PadLeft(NQubits, '0').Reverse() |
| 153 | + ), |
| 154 | + fromBase: 2 |
| 155 | + ) |
| 156 | + .ToString(), |
| 157 | + BasisStateLabelingConvention.LittleEndian => |
| 158 | + index.ToString(), |
| 159 | + _ => throw new ArgumentException($"Invalid basis state labeling convention {convention}.") |
| 160 | + }; |
| 161 | + |
| 162 | + /// <summary> |
| 163 | + /// Returns a string that represents the magnitude of the amplitude. |
| 164 | + /// </summary> |
| 165 | + public virtual string FormatMagnitude(double magnitude, double phase) => |
| 166 | + (new String('*', (int)System.Math.Ceiling(20.0 * magnitude))).PadRight(20) + $" [ {magnitude:F6} ]"; |
| 167 | + |
| 168 | + /// <summary> |
| 169 | + /// Returns a string that represents the phase of the amplitude. |
| 170 | + /// </summary> |
| 171 | + public virtual string FormatAngle(double magnitude, double angle) |
| 172 | + { |
| 173 | + var PI = System.Math.PI; |
| 174 | + var offset = PI / 16.0; |
| 175 | + if (magnitude == 0.0) |
| 176 | + { |
| 177 | + return " "; |
| 178 | + } |
| 179 | + |
| 180 | + var chart = " ---"; |
| 181 | + if (angle > 0) |
| 182 | + { |
| 183 | + if (angle >= (0 * PI / 8) + offset && angle < ((1 * PI / 8) + offset)) { chart = " /-"; } |
| 184 | + if (angle >= (1 * PI / 8) + offset && angle < ((2 * PI / 8) + offset)) { chart = " / "; } |
| 185 | + if (angle >= (2 * PI / 8) + offset && angle < ((3 * PI / 8) + offset)) { chart = " +/ "; } |
| 186 | + if (angle >= (3 * PI / 8) + offset && angle < ((4 * PI / 8) + offset)) { chart = " ↑ "; } |
| 187 | + if (angle >= (4 * PI / 8) + offset && angle < ((5 * PI / 8) + offset)) { chart = " \\- "; } |
| 188 | + if (angle >= (5 * PI / 8) + offset && angle < ((6 * PI / 8) + offset)) { chart = " \\ "; } |
| 189 | + if (angle >= (6 * PI / 8) + offset && angle < ((7 * PI / 8) + offset)) { chart = "+\\ "; } |
| 190 | + if (angle >= (7 * PI / 8) + offset) { chart = "--- "; } |
| 191 | + } |
| 192 | + else if (angle < 0) |
| 193 | + { |
| 194 | + var abs_angle = System.Math.Abs(angle); |
| 195 | + if (abs_angle >= (0 * PI / 8) + offset && abs_angle < ((1 * PI / 8) + offset)) { chart = " \\+"; } |
| 196 | + if (abs_angle >= (1 * PI / 8) + offset && abs_angle < ((2 * PI / 8) + offset)) { chart = " \\ "; } |
| 197 | + if (abs_angle >= (2 * PI / 8) + offset && abs_angle < ((3 * PI / 8) + offset)) { chart = " -\\ "; } |
| 198 | + if (abs_angle >= (3 * PI / 8) + offset && abs_angle < ((4 * PI / 8) + offset)) { chart = " ↓ "; } |
| 199 | + if (abs_angle >= (4 * PI / 8) + offset && abs_angle < ((5 * PI / 8) + offset)) { chart = " /+ "; } |
| 200 | + if (abs_angle >= (5 * PI / 8) + offset && abs_angle < ((6 * PI / 8) + offset)) { chart = " / "; } |
| 201 | + if (abs_angle >= (6 * PI / 8) + offset && abs_angle < ((7 * PI / 8) + offset)) { chart = "-/ "; } |
| 202 | + } |
| 203 | + |
| 204 | + return $" {chart} [ {angle,8:F5} rad ]"; |
| 205 | + } |
| 206 | + |
| 207 | + /// <summary> |
| 208 | + /// Returns a string for the amplitude's polar representation (magnitude/angle). |
| 209 | + /// </summary> |
| 210 | + public virtual string FormatPolar(double magnitude, double angle) => |
| 211 | + $"{FormatMagnitude(magnitude, angle)}{FormatAngle(magnitude, angle)}"; |
| 212 | + |
| 213 | + /// <summary> |
| 214 | + /// Returns a string for the amplitude's cartesian representation (real + imagnary). |
| 215 | + /// </summary> |
| 216 | + public virtual string FormatCartesian(double real, double img) => |
| 217 | + $"{real,9:F6} + {img,9:F6} i"; |
| 218 | + |
| 219 | + public string ToString(BasisStateLabelingConvention convention, // Non-override. Parameterized. |
| 220 | + bool truncateSmallAmplitudes, |
| 221 | + double truncationThreshold) |
| 222 | + { |
| 223 | + return string.Join('\n', |
| 224 | + SignificantAmplitudes(convention, truncateSmallAmplitudes, truncationThreshold) |
| 225 | + .Select( |
| 226 | + item => |
| 227 | + { |
| 228 | + var (cmplx, basisLabel) = item; |
| 229 | + var amplitude = (cmplx.Real * cmplx.Real) + (cmplx.Imaginary * cmplx.Imaginary); |
| 230 | + var angle = System.Math.Atan2(cmplx.Imaginary, cmplx.Real); |
| 231 | + return $"|{basisLabel}⟩\t{FormatCartesian(cmplx.Real, cmplx.Imaginary)}\t == \t" + |
| 232 | + $"{FormatPolar(amplitude, angle)}"; |
| 233 | + })); |
| 234 | + } |
| 235 | + |
| 236 | + public override string ToString() => // An override of the `object.ToString()`. |
| 237 | + ToString(BasisStateLabelingConvention.LittleEndian, false, 0.0); |
| 238 | + |
| 239 | + } |
| 240 | + |
| 241 | + } |
| 242 | +} |
0 commit comments