Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit dcb5b1a

Browse files
authored
Refactored the Dump functionality on Q#RT side. (#898)
1 parent 7736de7 commit dcb5b1a

File tree

7 files changed

+392
-216
lines changed

7 files changed

+392
-216
lines changed

src/Simulation/Simulators/CommonNativeSimulator/CommonNativeSimulator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ private protected CommonNativeSimulator(
3535

3636
public uint Id { get; protected set; }
3737

38+
public abstract uint[] QubitIds { get; }
39+
3840
public override string Name
3941
{
4042
get
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
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

Comments
 (0)