microsoft/qdk

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billt/mac-intel-cryptography

Branches

Tags

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

Clone

HTTPS

Download ZIP

library/chemistry/src/Generators.qs

230lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4export GeneratorIndex;
5export GeneratorSystem;
6export EvolutionGenerator;
7export HTermToGenIdx;
8export HTermsToGenSys;
9export HTermsToGenIdx;
10export MultiplexOperationsFromGenerator;
11
12import Std.Math.*;
13import Std.Arrays.*;
14
15/// # Summary
16/// Represents a single primitive term in the set of all dynamical generators, e.g.
17/// Hermitian operators, for which there exists a map from that generator
18/// to time-evolution by that generator, through an evolution set function.
19///
20/// The first element
21/// (Int[], Double[]) is indexes that single term -- For instance, the Pauli string
22/// XXY with coefficient 0.5 would be indexed by ([1,1,2], [0.5]). Alternatively,
23/// Hamiltonians parameterized by a continuous variable, such as X cos φ + Y sin φ,
24/// might for instance be represented by ([], [φ]). The second
25/// element indexes the subsystem on which the generator acts on.
26///
27/// # Remarks
28/// > [!WARNING]
29/// > The interpretation of an `GeneratorIndex` is not defined except
30/// > with reference to a particular set of generators.
31///
32/// # Example
33/// Using Pauli evolution set, the operator
34/// $\pi X_2 X_5 Y_9$ is represented as:
35/// ```qsharp
36/// let index = new GeneratorIndex {
37/// Term = ([1, 1, 2], [PI()]),
38/// Subsystem = [2, 5, 9]
39/// };
40/// ```
41struct GeneratorIndex {
42 Term : (Int[], Double[]),
43 Subsystem : Int[],
44}
45
46/// # Summary
47/// Represents a collection of `GeneratorIndex`es.
48///
49/// We iterate over this
50/// collection using a single-index integer, and the size of the
51/// collection is assumed to be known.
52struct GeneratorSystem {
53 NumEntries : Int,
54 EntryAt : (Int -> GeneratorIndex)
55}
56
57/// # Summary
58/// Represents a dynamical generator as a set of simulatable gates and
59/// an expansion in terms of that basis.
60///
61/// Last parameter for number of terms.
62struct EvolutionGenerator {
63 EvolutionSet : GeneratorIndex -> (Double, Qubit[]) => Unit is Adj + Ctl,
64 System : GeneratorSystem
65}
66
67/// # Summary
68/// Converts a Hamiltonian term to a GeneratorIndex.
69///
70/// # Input
71/// ## term
72/// Input data in `(Int[], Double[])` format.
73/// ## termType
74/// Additional information added to GeneratorIndex.
75///
76/// # Output
77/// A GeneratorIndex representing a Hamiltonian term represented by `term`,
78/// together with additional information added by `termType`.
79function HTermToGenIdx(term : (Int[], Double[]), termType : Int[]) : GeneratorIndex {
80 let (idxFermions, coeff) = term;
81 new GeneratorIndex { Term = (termType, coeff), Subsystem = idxFermions }
82}
83
84
85/// # Summary
86/// Converts an index to a Hamiltonian term in `(Int[], Double[])[]` data format to a GeneratorIndex.
87///
88/// # Input
89/// ## data
90/// Input data in `(Int[], Double[])[]` format.
91/// ## termType
92/// Additional information added to GeneratorIndex.
93/// ## idx
94/// Index to a term of the Hamiltonian
95///
96/// # Output
97/// A GeneratorIndex representing a Hamiltonian term represented by `data[idx]`,
98/// together with additional information added by `termType`.
99function HTermsToGenIdx(data : (Int[], Double[])[], termType : Int[], idx : Int) : GeneratorIndex {
100 return HTermToGenIdx(data[idx], termType);
101}
102
103
104/// # Summary
105/// Converts a Hamiltonian in `(Int[], Double[])[]` data format to a GeneratorSystem.
106///
107/// # Input
108/// ## data
109/// Input data in `(Int[], Double[])[]` format.
110/// ## termType
111/// Additional information added to GeneratorIndex.
112///
113/// # Output
114/// A GeneratorSystem representing a Hamiltonian represented by the input `data`.
115function HTermsToGenSys(data : (Int[], Double[])[], termType : Int[]) : GeneratorSystem {
116 new GeneratorSystem { NumEntries = Length(data), EntryAt = HTermsToGenIdx(data, termType, _) }
117}
118
119
120/// # Summary
121/// Applies a multiply-controlled unitary operation $U$ that applies a
122/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
123///
124/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
125///
126/// # Input
127/// ## unitaryGenerator
128/// A tuple where the first element `Int` is the number of unitaries $N$,
129/// and the second element `(Int -> ('T => () is Adj + Ctl))`
130/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
131/// operation $V_j$.
132///
133/// ## index
134/// $n$-qubit control register that encodes number states $\ket{j}$ in
135/// little-endian format.
136///
137/// ## target
138/// Generic qubit register that $V_j$ acts on.
139///
140/// # Remarks
141/// `coefficients` will be padded with identity elements if
142/// fewer than $2^n$ are specified. This implementation uses
143/// $n-1$ auxiliary qubits.
144///
145/// # References
146/// - [ *Andrew M. Childs, Dmitri Maslov, Yunseong Nam, Neil J. Ross, Yuan Su*,
147/// arXiv:1711.10980](https://arxiv.org/abs/1711.10980)
148operation MultiplexOperationsFromGenerator<'T>(unitaryGenerator : (Int, (Int -> ('T => Unit is Adj + Ctl))), index : Qubit[], target : 'T) : Unit is Ctl + Adj {
149 let (nUnitaries, unitaryFunction) = unitaryGenerator;
150 let unitaryGeneratorWithOffset = (nUnitaries, 0, unitaryFunction);
151 if Length(index) == 0 {
152 fail "MultiplexOperations failed. Number of index qubits must be greater than 0.";
153 }
154 if nUnitaries > 0 {
155 let auxiliary = [];
156 Adjoint MultiplexOperationsFromGeneratorImpl(unitaryGeneratorWithOffset, auxiliary, index, target);
157 }
158}
159
160/// # Summary
161/// Implementation step of `MultiplexOperationsFromGenerator`.
162operation MultiplexOperationsFromGeneratorImpl<'T>(unitaryGenerator : (Int, Int, (Int -> ('T => Unit is Adj + Ctl))), auxiliary : Qubit[], index : Qubit[], target : 'T) : Unit {
163 body (...) {
164 let nIndex = Length(index);
165 let nStates = 2^nIndex;
166
167 let (nUnitaries, unitaryOffset, unitaryFunction) = unitaryGenerator;
168
169 let nUnitariesLeft = MinI(nUnitaries, nStates / 2);
170 let nUnitariesRight = MinI(nUnitaries, nStates);
171
172 let leftUnitaries = (nUnitariesLeft, unitaryOffset, unitaryFunction);
173 let rightUnitaries = (nUnitariesRight - nUnitariesLeft, unitaryOffset + nUnitariesLeft, unitaryFunction);
174
175 let newControls = Most(index);
176
177 if nUnitaries > 0 {
178 if Length(auxiliary) == 1 and nIndex == 0 {
179 // Termination case
180
181 (Controlled Adjoint (unitaryFunction(unitaryOffset)))(auxiliary, target);
182 } elif Length(auxiliary) == 0 and nIndex >= 1 {
183 // Start case
184 let newauxiliary = Tail(index);
185 if nUnitariesRight > 0 {
186 MultiplexOperationsFromGeneratorImpl(rightUnitaries, [newauxiliary], newControls, target);
187 }
188 within {
189 X(newauxiliary);
190 } apply {
191 MultiplexOperationsFromGeneratorImpl(leftUnitaries, [newauxiliary], newControls, target);
192 }
193 } else {
194 // Recursion that reduces nIndex by 1 and sets Length(auxiliary) to 1.
195 let controls = [Tail(index)] + auxiliary;
196 use newauxiliary = Qubit();
197 use andauxiliary = Qubit[MaxI(0, Length(controls) - 2)];
198 within {
199 if Length(controls) == 0 {
200 X(newauxiliary);
201 } elif Length(controls) == 1 {
202 CNOT(Head(controls), newauxiliary);
203 } else {
204 let controls1 = controls[0..0] + andauxiliary;
205 let controls2 = Rest(controls);
206 let targets = andauxiliary + [newauxiliary];
207 for i in IndexRange(controls1) {
208 AND(controls1[i], controls2[i], targets[i]);
209 }
210 }
211
212 } apply {
213 if nUnitariesRight > 0 {
214 MultiplexOperationsFromGeneratorImpl(rightUnitaries, [newauxiliary], newControls, target);
215 }
216 within {
217 (Controlled X)(auxiliary, newauxiliary);
218 } apply {
219 MultiplexOperationsFromGeneratorImpl(leftUnitaries, [newauxiliary], newControls, target);
220 }
221 }
222 }
223 }
224 }
225 adjoint auto;
226 controlled (controlRegister, ...) {
227 MultiplexOperationsFromGeneratorImpl(unitaryGenerator, auxiliary + controlRegister, index, target);
228 }
229 controlled adjoint auto;
230}
231