microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fedimser/memory-re

Branches

Tags

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

Clone

HTTPS

Download ZIP

library/std/src/Std/Diagnostics.qs

504lines · modecode

1open QIR.Intrinsic;
2
3/// # Summary
4/// Dumps the current target machine's status.
5///
6/// # Description
7/// This method allows you to dump information about the current quantum state.
8/// The actual information generated and the semantics are specific to each target machine.
9///
10/// For the local sparse-state simulator distributed as part of the
11/// Quantum Development Kit, this method will write the wave function as a
12/// one-dimensional array of pairs of state indices and complex numbers, in which each element represents
13/// the amplitudes of the probability of measuring the corresponding state.
14///
15/// # Example
16/// When run on the sparse-state simulator, the following snippet dumps
17/// the Bell state (|00⟩ + |11⟩ ) / √2 to the console:
18/// ```qsharp
19/// use left = Qubit();
20/// use right = Qubit();
21/// within {
22/// H(left);
23/// CNOT(left, right);
24/// } apply {
25/// DumpMachine();
26/// }
27/// ```
28function DumpMachine() : Unit {
29 body intrinsic;
30}
31
32/// # Summary
33/// Dumps the current target machine's status associated with the given qubits.
34///
35/// # Input
36/// ## qubits
37/// The list of qubits to report.
38///
39/// # Remarks
40/// This method allows you to dump the information associated with the state of the
41/// given qubits.
42///
43/// For the local sparse-state simulator distributed as part of the
44/// Quantum Development Kit, this method will write the
45/// state of the given qubits (i.e. the wave function of the corresponding subsystem) as a
46/// one-dimensional array of pairs of state indices and complex numbers, in which each element represents
47/// the amplitudes of the probability of measuring the corresponding state.
48/// If the given qubits are entangled with some other qubit and their
49/// state can't be separated, it fails with a runtime error indicating that the qubits are entangled.
50///
51/// # Example
52/// When run on the sparse-state simulator, the following snippet dumps
53/// the Bell state (|00⟩ + |11⟩ ) / √2 to the console:
54/// ```qsharp
55/// use left = Qubit();
56/// use right = Qubit();
57/// within {
58/// H(left);
59/// CNOT(left, right);
60/// } apply {
61/// DumpRegister([left, right]);
62/// }
63/// ```
64function DumpRegister(register : Qubit[]) : Unit {
65 body intrinsic;
66}
67
68/// # Summary
69/// Given an operation, dumps the matrix representation of the operation action on the given
70/// number of qubits.
71///
72/// # Input
73/// ## nQubits
74/// The number of qubits on which the given operation acts.
75/// ## op
76/// The operation that is to be diagnosed.
77///
78/// # Remarks
79/// When run on the sparse-state simulator, the following snippet
80/// will output the matrix
81/// $\left(\begin{matrix} 0.707 & 0.707 \\\\ 0.707 & -0.707\end{matrix}\right)$:
82///
83/// ```qsharp
84/// operation DumpH() : Unit {
85/// DumpOperation(1, qs => H(qs[0]));
86/// }
87/// ```
88/// Calling this operation has no observable effect from within Q#.
89/// Note that if `DumpOperation` is called when there are other qubits allocated,
90/// the matrix displayed may reflect any global phase that has accumulated from operations
91/// on those other qubits.
92@SimulatableIntrinsic()
93operation DumpOperation(nQubits : Int, op : Qubit[] => Unit) : Unit {
94 use (targets, extra) = (Qubit[nQubits], Qubit[nQubits]);
95 for i in 0..nQubits - 1 {
96 H(targets[i]);
97 CNOT(targets[i], extra[i]);
98 }
99 op(targets);
100 DumpMatrix(targets + extra);
101 ResetAll(targets + extra);
102}
103
104function DumpMatrix(qs : Qubit[]) : Unit {
105 body intrinsic;
106}
107
108/// # Summary
109/// Checks whether a qubit is in the |0⟩ state, returning true if it is.
110///
111/// # Description
112/// This operation checks whether a qubit is in the |0⟩ state. It will return true only
113/// if the qubit is deterministically in the |0⟩ state, and will return false otherwise. This operation
114/// does not change the state of the qubit.
115///
116/// # Input
117/// ## qubit
118/// The qubit to check.
119/// # Output
120/// True if the qubit is in the |0⟩ state, false otherwise.
121///
122/// # Remarks
123/// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check
124/// this on hardware without measuring the qubit, which could change the state.
125operation CheckZero(qubit : Qubit) : Bool {
126 body intrinsic;
127}
128
129/// # Summary
130/// Checks whether all qubits in the provided array are in the |0⟩ state. Returns true if they are.
131///
132/// # Description
133/// This operation checks whether all qubits in the provided array are in the |0⟩ state. It will return true only
134/// if all qubits are deterministically in the |0⟩ state, and will return false otherwise. This operation
135/// does not change the state of the qubits.
136///
137/// # Input
138/// ## qubits
139/// The qubits to check.
140/// # Output
141/// True if all qubits are in the |0⟩ state, false otherwise.
142///
143/// # Remarks
144/// This operation is useful for checking whether a qubit is in the |0⟩ state during simulation. It is not possible to check
145/// this on hardware without measuring the qubit, which could change the state.
146operation CheckAllZero(qubits : Qubit[]) : Bool {
147 for q in qubits {
148 if not CheckZero(q) {
149 return false;
150 }
151 }
152
153 return true;
154}
155
156/// # Summary
157/// Checks whether a given condition is false, failing with a message if it is.
158///
159/// # Description
160/// This function checks the given condition. If the condition is false, the operation fails with the given message,
161/// terminating the program.
162///
163/// # Input
164/// ## actual
165/// The condition to check.
166/// ## message
167/// The message to use in the failure if the condition is false.
168@SimulatableIntrinsic()
169function Fact(actual : Bool, message : String) : Unit {
170 if (not actual) {
171 fail message;
172 }
173}
174
175/// # Summary
176/// Given two operations, checks that they act identically for all input states.
177///
178/// # Description
179/// This check is implemented by using the Choi–Jamiołkowski isomorphism to reduce
180/// this check to a check on two entangled registers.
181/// Thus, this operation needs only a single call to each operation being tested,
182/// but requires twice as many qubits to be allocated.
183/// This check can be used to ensure, for instance, that an optimized version of an
184/// operation acts identically to its naïve implementation, or that an operation
185/// which acts on a range of non-quantum inputs agrees with known cases.
186///
187/// # Remarks
188/// This operation requires that the operation modeling the expected behavior is
189/// adjointable, so that the inverse can be performed on the target register alone.
190/// Formally, one can specify a transpose operation, which relaxes this requirement,
191/// but the transpose operation is not in general physically realizable for arbitrary
192/// quantum operations and thus is not included here as an option.
193///
194/// # Input
195/// ## nQubits
196/// Number of qubits to pass to each operation.
197/// ## actual
198/// Operation to be tested.
199/// ## expected
200/// Operation defining the expected behavior for the operation under test.
201/// # Output
202/// True if operations are equal, false otherwise.
203operation CheckOperationsAreEqual(
204 nQubits : Int,
205 actual : (Qubit[] => Unit),
206 expected : (Qubit[] => Unit is Adj)
207) : Bool {
208
209 // Prepare a reference register entangled with the target register.
210 use reference = Qubit[nQubits];
211 use target = Qubit[nQubits];
212
213 // Apply operations.
214 within {
215 for i in 0..nQubits - 1 {
216 H(reference[i]);
217 CNOT(reference[i], target[i]);
218 }
219 } apply {
220 actual(target);
221 Adjoint expected(target);
222 }
223
224 // Check and return result.
225 let areEqual = CheckAllZero(reference) and CheckAllZero(target);
226 ResetAll(target);
227 ResetAll(reference);
228 areEqual
229}
230
231/// # Summary
232/// Starts counting the number of times the given operation is called. Fails if the operation is already being counted.
233///
234/// # Description
235/// This operation allows you to count the number of times a given operation is called. If the given operation is already
236/// being counted, calling `StartCountingOperation` again will trigger a runtime failure. Counting is based on the specific
237/// specialization of the operation invoked, so `X` and `Adjoint X` are counted separately.
238/// Likewise `Controlled X`, `CNOT`, and `CX` are independent operations that are counted separately, as are `Controlled X`
239/// and `Controlled Adjoint X`.
240///
241/// # Input
242/// ## callable
243/// The operation to be counted.
244///
245/// # Remarks
246/// Counting operation calls requires specific care in what operation is passed as input. For example, `StartCountingOperation(H)` will
247/// count only the number of times `H` is called, while `StartCountingOperation(Adjoint H)` will count only the number of times `Adjoint H` is called, even
248/// though `H` is self-adjoint. This is due to how the execution treats the invocation of these operations as distinct by their specialization.
249/// In the same way, `StartCountingOperation(Controlled X)` will count only the number of times `Controlled X` is called, while
250/// `StartCountingOperation(CNOT)` will count only the number of times `CNOT` is called.
251///
252/// When counting lambdas, the symbol the lambda is bound to is used to identify the operation and it is counted as a separate operation. For example,
253/// ```qsharp
254/// let myOp = q => H(q);
255/// StartCountingOperation(myOp);
256/// ```
257/// Will count specifically calls to `myOp` and not `H`. By contrast, the following code will count calls to `H` itself:
258/// ```qsharp
259/// let myOp = H;
260/// StartCountingOperation(myOp);
261/// ```
262/// This is because this code does not define a lambda and instead just creates a binding to `H` directly.
263@Config(Unrestricted)
264operation StartCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Unit {
265 body intrinsic;
266}
267
268/// # Summary
269/// Stops counting the number of times the given operation is called and returns the count. Fails
270/// if the operation was not being counted.
271///
272/// # Description
273/// This operation allows you to stop counting the number of times a given operation is called and returns the count.
274/// If the operation was not being counted, it triggers a runtime failure.
275///
276/// # Input
277/// ## callable
278/// The operation whose count will be returned.
279/// # Output
280/// The number of times the operation was called since the last call to `StartCountingOperation`.
281@Config(Unrestricted)
282operation StopCountingOperation<'In, 'Out>(callable : 'In => 'Out) : Int {
283 body intrinsic;
284}
285
286/// # Summary
287/// Starts counting the number of times the given function is called. Fails if the function is already being counted.
288///
289/// # Description
290/// This operation allows you to count the number of times a given function is called. If the given function is already
291/// being counted, calling `StartCountingFunction` again will trigger a runtime failure.
292///
293/// # Input
294/// ## callable
295/// The function to be counted.
296///
297/// # Remarks
298/// When counting lambdas, the symbol the lambda is bound to is used to identify the function and it is counted as a separate function. For example,
299/// ```qsharp
300/// let myFunc = i -> AbsI(i);
301/// StartCountingFunction(myFunc);
302/// ```
303/// Will count specifically calls to `myFunc` and not `AbsI`. By contrast, the following code will count calls to `AbsI` itself:
304/// ```qsharp
305/// let myFunc = AbsI;
306/// StartCountingFunction(myFunc);
307/// ```
308/// This is because this code does not define a lambda and instead just creates a binding to `AbsI` directly.
309@Config(Unrestricted)
310operation StartCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Unit {
311 body intrinsic;
312}
313
314/// # Summary
315/// Stops counting the number of times the given function is called and returns the count. Fails
316/// if the function was not being counted.
317///
318/// # Description
319/// This operation allows you to stop counting the number of times a given function is called and returns the count.
320/// If the function was not being counted, it triggers a runtime failure.
321///
322/// # Input
323/// ## callable
324/// The function whose count will be returned.
325/// # Output
326/// The number of times the function was called since the last call to `StartCountingFunction`.
327@Config(Unrestricted)
328operation StopCountingFunction<'In, 'Out>(callable : 'In -> 'Out) : Int {
329 body intrinsic;
330}
331
332/// # Summary
333/// Starts counting the number of qubits allocated. Fails if qubits are already being counted.
334///
335/// # Description
336/// This operation allows you to count the number of qubits allocated until `StopCountingQubits` is called.
337/// The counter is incremented only when a new unique qubit is allocated, so reusing the same qubit multiple times
338/// across separate allocations does not increment the counter.
339///
340/// # Remarks
341/// This operation is useful for tracking the number of unique qubits allocated in a given scope. Along with
342/// `StopCountingQubits`, it can be used to verify that a given operation does not allocate more qubits than
343/// expected. For example,
344/// ```qsharp
345/// StartCountingQubits();
346/// testOperation();
347/// let qubitsAllocated = StopCountingQubits();
348/// Fact(qubitsAllocated <= 4, "Operation should not allocate more than 4 qubits.");
349/// ```
350@Config(Unrestricted)
351operation StartCountingQubits() : Unit {
352 body intrinsic;
353}
354
355/// # Summary
356/// Stops counting the number of qubits allocated and returns the count. Fails if the qubits were not being counted.
357///
358/// # Description
359/// This operation allows you to stop counting the number of qubits allocated and returns the count since the
360/// last call to `StartCountingQubits`. If the qubits were not being counted, it triggers a runtime failure.
361///
362/// # Output
363/// The number of unique qubits allocated since the last call to `StartCountingQubits`.
364@Config(Unrestricted)
365operation StopCountingQubits() : Int {
366 body intrinsic;
367}
368
369/// # Summary
370/// Configures Pauli noise for simulation.
371///
372/// # Description
373/// This function configures Pauli noise for simulation. Parameters represent
374/// probabilities of applying X, Y, and Z gates and must add up to at most 1.0.
375/// Noise is applied after each gate and before each measurement in the simulator
376/// backend. Decompositions may affect the number of times noise is applied.
377/// Use 0.0 for all parameters to simulate without noise.
378///
379/// # Input
380/// ## px
381/// Probability of applying X gate.
382/// ## py
383/// Probability of applying Y gate.
384/// ## pz
385/// Probability of applying Z gate.
386function ConfigurePauliNoise(px : Double, py : Double, pz : Double) : Unit {
387 body intrinsic;
388}
389
390/// # Summary
391/// Configures qubit loss during simulation.
392///
393/// # Description
394/// This function configures qubit loss for simulation. The parameter `p` represents
395/// the probability of a qubit loss during simulation. If `p` is greater than 0.0, the simulator will mark qubits
396/// as lost with the given probability during each operation that acts on them.
397/// Qubits that are lost are reset to the |0⟩ state but are not released. Loss is reported when the qubit is measured,
398/// and then the qubit is considered "reloaded" and can be used again.
399///
400/// # Input
401/// ## p
402/// The probability of a qubit being lost during simulation. Must be between 0.0 and 1.0.
403///
404/// # Remarks
405/// This operation is useful for simulating qubit loss for those modalities where qubit loss is a factor.
406/// Note that the value returned from a measurement of a lost qubit is neither `Zero` nor `One`, but rather a special
407/// value indicating that the qubit was lost. This value cannot be used in comparisons and will cause a runtime
408/// failure if compared to another value.
409/// To perform a measurement that includes a check for qubit loss, use the `MResetZChecked` operation.
410function ConfigureQubitLoss(p : Double) : Unit {
411 body intrinsic;
412}
413
414/// # Summary
415/// Applies configured noise or loss to a qubit.
416///
417/// # Description
418/// This operation applies configured noise and/or loss to a qubit during simulation. For example,
419/// if configured noise is a bit-flip noise with 5% probability, the X gate will be applied
420/// with 5% probability. If no noise is configured, no noise is applied.
421/// This is useful to simulate noise during idle periods. It could also be used to
422/// apply noise immediately after qubit allocation.
423///
424/// # Input
425/// ## qubit
426/// The qubit to which noise is applied.
427///
428/// # See Also
429/// - [Std.Diagnostics.ConfigurePauliNoise](xref:Qdk.Std.Diagnostics.ConfigurePauliNoise)
430/// - [Std.Diagnostics.ConfigureQubitLoss](xref:Qdk.Std.Diagnostics.ConfigureQubitLoss)
431operation ApplyIdleNoise(qubit : Qubit) : Unit {
432 body intrinsic;
433}
434
435/// # Summary
436/// The bit flip noise with probability `p`.
437function BitFlipNoise(p : Double) : (Double, Double, Double) {
438 (p, 0.0, 0.0)
439}
440
441/// # Summary
442/// The phase flip noise with probability `p`.
443function PhaseFlipNoise(p : Double) : (Double, Double, Double) {
444 (0.0, 0.0, p)
445}
446
447/// # Summary
448/// The depolarizing noise with probability `p`.
449function DepolarizingNoise(p : Double) : (Double, Double, Double) {
450 (p / 3.0, p / 3.0, p / 3.0)
451}
452
453/// # Summary
454/// No noise for noiseless operation.
455function NoNoise() : (Double, Double, Double) {
456 (0.0, 0.0, 0.0)
457}
458
459/// # Summary
460/// Post-selects on the given qubit being in the given state in the computational basis.
461///
462/// # Description
463/// During simulation, this operation forces the collapse of the qubit into the state as long
464/// as that state has a non-zero probability of being measured, and will trigger a runtime
465/// failure if the state has zero probability of being measured.
466/// During resource estimation, this operation forces the next measurement of the qubit to
467/// return the given result, regardless of any state, allowing for estimation of specific
468/// branches of an adaptive algorithm.
469///
470/// # Input
471/// ## res
472/// The result corresponding to the state to post-select on.
473/// ## qubit
474/// The qubit to post-select on.
475///
476/// # Remarks
477/// This operation is useful for testing, simulation, and estimation purposes, but has
478/// no physical meaning and is not implementable on hardware.
479operation PostSelectZ(res : Result, qubit : Qubit) : Unit {
480 body intrinsic;
481}
482
483export
484 DumpMachine,
485 DumpRegister,
486 DumpOperation,
487 CheckZero,
488 CheckAllZero,
489 Fact,
490 CheckOperationsAreEqual,
491 StartCountingOperation,
492 StopCountingOperation,
493 StartCountingFunction,
494 StopCountingFunction,
495 StartCountingQubits,
496 StopCountingQubits,
497 ConfigurePauliNoise,
498 ConfigureQubitLoss,
499 ApplyIdleNoise,
500 BitFlipNoise,
501 PhaseFlipNoise,
502 DepolarizingNoise,
503 NoNoise,
504 PostSelectZ;
505