microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
sccarda/PythonApiDocs

Branches

Tags

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

Clone

HTTPS

Download ZIP

library/chemistry/src/JordanWigner/OptimizedBEOperator.qs

168lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4export OptimizedBEXY;
5
6import Std.Arrays.IndexRange;
7import Std.Arrays.Partitioned;
8import Std.Math.Max;
9
10import Generators.MultiplexOperationsFromGenerator;
11
12/// # Summary
13/// Applies a sequence of Z operations and either an X or Y operation to
14/// a register of qubits, where the selection of target qubits and basis
15/// are conditioned on the state of a control register.
16///
17/// # Description
18/// This operation can be described by a unitary matrix $U$ that applies
19/// the Pauli string on $(X^{z+1}\_pY^{z}\_p)Z\_{p-1}...Z_0$ on
20/// qubits $0..p$ conditioned on an index $z\in\{0,1\}$ and $p$.
21///
22/// That is,
23/// $$
24/// \begin{align}
25/// U\ket{z}\ket{p}\ket{\psi} = \ket{z}\ket{p}(X^{z+1}\_pY^{z}\_p)Z\_{p-1}...Z_0\ket{\psi}
26/// \end{align}
27/// $$
28///
29/// # Input
30/// ## pauliBasis
31/// When this qubit is in state $\ket{0}$, an `X` operation is applied. When it is in state $\ket{1}$, `Y` is applied.
32/// ## indexRegister
33/// The state $\ket{p}$ of this register determines the qubit on which `X` or `Y` is applied.
34/// ## targetRegister
35/// Register of qubits on which the Pauli operators are applied.
36///
37/// # References
38/// - [Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity](https://arxiv.org/abs/1805.03662)
39/// Ryan Babbush, Craig Gidney, Dominic W. Berry, Nathan Wiebe, Jarrod McClean, Alexandru Paler, Austin Fowler, Hartmut Neven
40operation OptimizedBEXY(
41 pauliBasis : Qubit,
42 indexRegister : Qubit[],
43 targetRegister : Qubit[]
44) : Unit is Adj + Ctl {
45 let unitaryGenerator = (Length(targetRegister), idx -> OptimizedBEXYImpl(idx, _, _, _));
46
47 use accumulator = Qubit();
48
49 // This assumes that MultiplexOperationsFromGenerator applies unitaries indexed in unitaryGenerator in ascending order.
50 X(accumulator);
51 MultiplexOperationsFromGenerator(unitaryGenerator, indexRegister, (pauliBasis, accumulator, targetRegister));
52 // If indexRegister encodes an integer that is larger than Length(targetRegister),
53 // _OptimizedBEXY_ will fail due to an out of range error. In this situation,
54 // releasing the accumulator qubit will throw an error as it will be in the One state.
55}
56
57// Subroutine of OptimizedBEXY.
58operation OptimizedBEXYImpl(
59 targetIndex : Int,
60 pauliBasis : Qubit,
61 accumulator : Qubit,
62 targetRegister : Qubit[]
63) : Unit is Adj + Ctl {
64
65 body (...) {
66 // This should always be called as a controlled operation.
67 fail "_OptimizedBEXY should always be called as a controlled operation.";
68 }
69
70 controlled (ctrl, ...) {
71 if Length(targetRegister) <= targetIndex {
72 fail "targetIndex out of range.";
73 }
74
75 Controlled X(ctrl, accumulator);
76 within {
77 Controlled Adjoint S([pauliBasis], targetRegister[targetIndex]);
78 } apply {
79 Controlled X(ctrl, targetRegister[targetIndex]);
80 }
81 Controlled Z([accumulator], targetRegister[targetIndex]);
82 }
83
84}
85
86/// # Summary
87/// Applies a Z operation to a qubit indicated by the state of another
88/// register.
89///
90/// # Description
91/// The operation can be represented by a unitary matrix $U$ that applies
92/// the `Std.Intrinsic.Z` operation on a qubit $p$
93/// conditioned on an index state $\ket{p}$. That is,
94/// $$
95/// \begin{align}
96/// U\ket{p}\ket{\psi} = \ket{p}Z\_p\ket{\psi}.
97/// \end{align}
98/// $$
99///
100/// # Input
101/// ## indexRegister
102/// A register in the state $\ket{p}$, determining the qubit on which $Z$ is applied.
103/// ## targetRegister
104/// Register of qubits on which the Pauli operators are applied.
105operation SelectZ(indexRegister : Qubit[], targetRegister : Qubit[]) : Unit is Adj + Ctl {
106 let unitaryGenerator = (Length(targetRegister), idx -> (qs => Z(qs[idx])));
107 MultiplexOperationsFromGenerator(unitaryGenerator, indexRegister, targetRegister);
108 // If indexRegister encodes an integer that is larger than Length(targetRegister),
109 // _SelectZ_ will fail due to an out of range error. In this situation,
110 // releasing the accumulator qubit will throw an error as it will be in the One state.
111}
112
113operation JWSelect(
114 signQubit : Qubit,
115 selectZControlRegisters : Qubit[],
116 OptimizedBEControlRegisters : Qubit[],
117 pauliBases : Qubit[],
118 indexRegisters : Qubit[][],
119 targetRegister : Qubit[]
120) : Unit is Adj + Ctl {
121 Z(signQubit);
122
123 for idxRegister in IndexRange(OptimizedBEControlRegisters) {
124 Controlled OptimizedBEXY(
125 [OptimizedBEControlRegisters[idxRegister]],
126 (pauliBases[idxRegister], indexRegisters[idxRegister], targetRegister)
127 );
128 }
129
130 for idxRegister in IndexRange(selectZControlRegisters) {
131 Controlled SelectZ([selectZControlRegisters[idxRegister]], (indexRegisters[idxRegister], targetRegister));
132 }
133}
134
135function JWSelectQubitCount(nZ : Int, nMaj : Int, nIdxRegQubits : Int) : (Int, (Int, Int, Int, Int, Int[])) {
136 let signQubit = 1;
137 let selectZControlRegisters = nZ;
138 let OptimizedBEControlRegisters = nMaj;
139 let pauliBases = nMaj;
140 let indexRegisters = Repeated(nIdxRegQubits, Max([nZ, nMaj]));
141 let nTotal = ((1 + nZ) + 2 * nMaj) + Max([nZ, nMaj]) * nIdxRegQubits;
142 return (nTotal, (signQubit, selectZControlRegisters, OptimizedBEControlRegisters, pauliBases, indexRegisters));
143}
144
145function JWSelectQubitManager(
146 nZ : Int,
147 nMaj : Int,
148 nIdxRegQubits : Int,
149 ctrlRegister : Qubit[],
150 targetRegister : Qubit[]
151) : ((Qubit, Qubit[], Qubit[], Qubit[], Qubit[][], Qubit[]), Qubit[]) {
152 let (nTotal, (a, b, c, d, e)) = JWSelectQubitCount(nZ, nMaj, nIdxRegQubits);
153 let split = [a, b, c, d] + e;
154 let registers = Partitioned(split, ctrlRegister);
155 let signQubit = registers[0];
156 let selectZControlRegisters = registers[1];
157 let OptimizedBEControlRegisters = registers[2];
158 let pauliBases = registers[3];
159 let indexRegistersTmp = registers[4..(4 + Length(e)) - 1];
160 let rest = registers[Length(registers) - 1];
161
162 mutable indexRegisters = [];
163 for idx in IndexRange(e) {
164 indexRegisters += [indexRegistersTmp[idx]];
165 }
166
167 return ((signQubit[0], selectZControlRegisters, OptimizedBEControlRegisters, pauliBases, indexRegisters, targetRegister), rest);
168}
169