microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
sccarda/BlochLearning

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

library/std/src/Std/OpenQASM/Angle.qs

257lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4/// This file defines the Angle type and its associated functions.
5/// It is an internal implementation detail for OpenQASM compilation
6/// and is not intended for use outside of this context.
7
8// Export the Angle type and its associated functions.
9export Angle;
10// Export the array conversion functions for Angle.
11export AngleAsBoolArrayBE, AngleAsResultArrayBE, ResultArrayAsAngleBE;
12// Export cast from Angle to other types.
13export AngleAsDouble, AngleAsBool, AngleAsResult;
14// Export cast from other types to Angle.
15export IntAsAngle, DoubleAsAngle, ResultAsAngle;
16// Export width conversion functions for Angle.
17export AdjustAngleSizeNoTruncation;
18// Export bitwise operations on Angle.
19export AngleShl, AngleShr, AngleNotB, AngleAndB, AngleOrB, AngleXorB;
20// Export comparison functions for Angle.
21export AngleEq, AngleNeq, AngleGt, AngleGte, AngleLt, AngleLte;
22// Export symmetric functions.
23export AddAngles, SubtractAngles, DivideAngleByAngle, NegAngle;
24// Export asymmetric functions.
25export MultiplyAngleByInt, MultiplyAngleByBigInt, DivideAngleByInt;
26
27
28struct Angle {
29 Value : Int,
30 Size : Int
31}
32
33function AngleAsBoolArrayBE(angle : Angle) : Bool[] {
34 Std.Arrays.Reversed(Std.Convert.IntAsBoolArray(angle.Value, angle.Size))
35}
36
37function AngleAsDouble(angle : Angle) : Double {
38 let F64_MANTISSA_DIGITS = 53;
39 let angle = if angle.Size > F64_MANTISSA_DIGITS {
40 AdjustAngleSize(angle, F64_MANTISSA_DIGITS, false)
41 } else {
42 angle
43 };
44 let denom = Std.Convert.IntAsDouble(1 <<< angle.Size);
45 let value = Std.Convert.IntAsDouble(angle.Value);
46 let factor = (2.0 * Std.Math.PI()) / denom;
47 value * factor
48}
49
50function AngleAsBool(angle : Angle) : Bool {
51 return angle.Value != 0;
52}
53
54function ResultAsAngle(result : Result) : Angle {
55 new Angle { Value = Std.OpenQASM.Convert.ResultAsInt(result), Size = 1 }
56}
57
58function AngleAsResult(angle : Angle) : Result {
59 Std.Convert.BoolAsResult(angle.Value != 0)
60}
61
62/// The ``AngleAsResultArrayBE`` function is used to implement the cast expr in QASM for angle[n] to bit[n].
63/// with big-endian order. This is needed for round-trip conversion for bin ops.
64function AngleAsResultArrayBE(angle : Angle) : Result[] {
65 Std.OpenQASM.Convert.IntAsResultArrayBE(angle.Value, angle.Size)
66}
67
68function IntAsAngle(value : Int, size : Int) : Angle {
69 Std.Diagnostics.Fact(value >= 0, "Value must be >= 0");
70 Std.Diagnostics.Fact(size > 0, "Size must be > 0");
71 new Angle { Value = value, Size = size }
72}
73
74/// The ``ResultArrayAsAngleBE`` function is used to implement the cast expr in QASM for bit[n] to angle[n].
75/// with big-endian order. This is needed for round-trip conversion for bin ops.
76function ResultArrayAsAngleBE(array : Result[]) : Angle {
77 IntAsAngle(Std.OpenQASM.Convert.ResultArrayAsIntBE(array), Length(array))
78}
79
80function DoubleAsAngle(value : Double, size : Int) : Angle {
81 let tau : Double = 2. * Std.Math.PI();
82
83 mutable value = value % tau;
84 if value < 0. {
85 value = value + tau;
86 }
87
88 // Handle the edge case where modulo returns tau due to floating-point precision
89 // we've seen this when the user rotates by f64::EPSILON / 2.0 causing the value
90 // to be still equal to tau after the modulo operation.
91 if value >= tau {
92 value = 0.;
93 }
94
95 Std.Diagnostics.Fact(value >= 0., "Value must be >= 0.");
96 Std.Diagnostics.Fact(value < tau, "Value must be < tau.");
97 Std.Diagnostics.Fact(size > 0, "Size must be > 0");
98
99
100 let factor = tau / Std.Convert.IntAsDouble(1 <<< size);
101 let value = Std.Math.RoundHalfAwayFromZero(value / factor);
102 new Angle { Value = value, Size = size }
103}
104
105function AdjustAngleSizeNoTruncation(angle : Angle, new_size : Int) : Angle {
106 AdjustAngleSize(angle, new_size, false)
107}
108
109function AdjustAngleSize(angle : Angle, new_size : Int, truncate : Bool) : Angle {
110 Std.Diagnostics.Fact(new_size > 0, "New size must be > 0");
111 let (value, size) = (angle.Value, angle.Size);
112 if new_size < size {
113 let value = if truncate {
114 let shift_amount = size - new_size;
115 value >>> shift_amount
116 } else {
117 // Rounding
118 let shift_amount = size - new_size;
119 let half = 1 <<< (shift_amount - 1);
120 let mask = (1 <<< shift_amount) - 1;
121 let lower_bits = value &&& mask;
122 let upper_bits = value >>> shift_amount;
123 if lower_bits > half or (lower_bits == half and (upper_bits &&& 1) == 1) {
124 upper_bits + 1
125 } else {
126 upper_bits
127 }
128 };
129 new Angle { Value = value, Size = new_size }
130 } elif new_size == size {
131 // Same size, no change
132 angle
133 } else {
134 // Padding with zeros
135 let value = value <<< (new_size - size);
136 new Angle { Value = value, Size = new_size }
137 }
138}
139
140// Bit shift
141
142function AngleShl(angle : Angle, operand : Int) : Angle {
143 Std.Diagnostics.Fact(operand >= 0, "Shift amount must be >= 0");
144 let mask = (1 <<< angle.Size) - 1;
145 let value = (angle.Value <<< operand) &&& mask;
146 new Angle { Value = value, Size = angle.Size }
147}
148
149function AngleShr(angle : Angle, operand : Int) : Angle {
150 Std.Diagnostics.Fact(operand >= 0, "Shift amount must be >= 0");
151 let value = (angle.Value >>> operand);
152 new Angle { Value = value, Size = angle.Size }
153}
154
155// Bitwise
156
157function AngleNotB(angle : Angle) : Angle {
158 let mask = (1 <<< angle.Size) - 1;
159 let value = (~~~angle.Value) &&& mask;
160 new Angle { Value = value, Size = angle.Size }
161}
162
163function AngleAndB(lhs : Angle, rhs : Angle) : Angle {
164 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
165 let value = lhs.Value &&& rhs.Value;
166 new Angle { Value = value, Size = lhs.Size }
167}
168
169function AngleOrB(lhs : Angle, rhs : Angle) : Angle {
170 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
171 let value = lhs.Value ||| rhs.Value;
172 new Angle { Value = value, Size = lhs.Size }
173}
174
175function AngleXorB(lhs : Angle, rhs : Angle) : Angle {
176 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
177 let value = lhs.Value ^^^ rhs.Value;
178 new Angle { Value = value, Size = lhs.Size }
179}
180
181// Comparison
182
183function AngleEq(lhs : Angle, rhs : Angle) : Bool {
184 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
185 lhs.Value == rhs.Value
186}
187
188function AngleNeq(lhs : Angle, rhs : Angle) : Bool {
189 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
190 lhs.Value != rhs.Value
191}
192
193function AngleGt(lhs : Angle, rhs : Angle) : Bool {
194 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
195 lhs.Value > rhs.Value
196}
197
198function AngleGte(lhs : Angle, rhs : Angle) : Bool {
199 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
200 lhs.Value >= rhs.Value
201}
202
203function AngleLt(lhs : Angle, rhs : Angle) : Bool {
204 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
205 lhs.Value < rhs.Value
206}
207
208function AngleLte(lhs : Angle, rhs : Angle) : Bool {
209 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
210 lhs.Value <= rhs.Value
211}
212
213// Arithmetic
214
215function AddAngles(lhs : Angle, rhs : Angle) : Angle {
216 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
217 let value = (lhs.Value + rhs.Value) % (1 <<< lhs.Size);
218 new Angle { Value = value, Size = lhs.Size }
219}
220
221function SubtractAngles(lhs : Angle, rhs : Angle) : Angle {
222 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
223 let value = (lhs.Value + ((1 <<< lhs.Size) - rhs.Value)) % (1 <<< lhs.Size);
224 new Angle { Value = value, Size = lhs.Size }
225}
226
227function MultiplyAngleByInt(angle : Angle, factor : Int) : Angle {
228 Std.Diagnostics.Fact(factor >= 0, "Factor amount must be >= 0");
229 let value = (angle.Value * factor) % (1 <<< angle.Size);
230 new Angle { Value = value, Size = angle.Size }
231}
232
233function MultiplyAngleByBigInt(angle : Angle, factor : BigInt) : Angle {
234 Std.Diagnostics.Fact(factor >= 0L, "Factor amount must be >= 0");
235 let value : BigInt = Std.Convert.IntAsBigInt(angle.Value);
236 let value = (value * factor) % Std.Convert.IntAsBigInt(1 <<< angle.Size);
237 let value = Std.Convert.BigIntAsInt(value);
238 new Angle { Value = value, Size = angle.Size }
239}
240
241function DivideAngleByAngle(lhs : Angle, rhs : Angle) : Int {
242 Std.Diagnostics.Fact(lhs.Size == rhs.Size, "Angle sizes must be the same");
243 let value = lhs.Value / rhs.Value;
244 value
245}
246
247function DivideAngleByInt(angle : Angle, divisor : Int) : Angle {
248 Std.Diagnostics.Fact(divisor > 0, "Divisor amount must be > 0");
249 let value = angle.Value / divisor;
250 new Angle { Value = value, Size = angle.Size }
251}
252
253function NegAngle(angle : Angle) : Angle {
254 let (value, size) = (angle.Value, angle.Size);
255 let value = ((1 <<< size) - value) % (1 <<< size);
256 new Angle { Value = value, Size = size }
257}
258