Skip to content

Commit 5c7522c

Browse files
DmitryVasilevskyDmitry Vasilevsky
andauthored
Refactoring of chemistry library (microsoft#2208)
Refactoring of chemistry library - major renaming and rearranging. Backwards compatibility is not maintained. - Files in JordanWigner folder are renamed without JordanWigner prefix. - Some functions and structures in those files are renamed to include JW prefix instead of fully spelled JordanWigner. Some are renamed without prefix entirely (local to a file). - Some functions are moved to new files (like Generators.qs, Oracles.qs, Trotterization.qs, MixedStatePreparation.qs). Some files are renamed (like VQE.qs), some functions are grouped in the same file. - Formatting changed to break very long lines and other formatting changes. - Removed 'All Rights Reserved' from headers. - Removed output from sample notebook. - Other misc. updates. --------- Co-authored-by: Dmitry Vasilevsky <[email protected]>
1 parent 1901967 commit 5c7522c

18 files changed

+1364
-2406
lines changed

library/chemistry/qsharp.json

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,19 @@
4242
}
4343
],
4444
"files": [
45+
"src/Generators.qs",
46+
"src/MixedStatePreparation.qs",
4547
"src/Tests.qs",
48+
"src/Trotterization.qs",
4649
"src/Utils.qs",
47-
"src/JordanWigner/Convenience.qs",
48-
"src/JordanWigner/ConvenienceVQE.qs",
49-
"src/JordanWigner/JordanWignerBlockEncoding.qs",
50-
"src/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs",
51-
"src/JordanWigner/JordanWignerEvolutionSet.qs",
52-
"src/JordanWigner/JordanWignerOptimizedBlockEncoding.qs",
53-
"src/JordanWigner/JordanWignerVQE.qs",
50+
"src/JordanWigner/Oracles.qs",
51+
"src/JordanWigner/VQE.qs",
52+
"src/JordanWigner/Data.qs",
53+
"src/JordanWigner/BlockEncoding.qs",
54+
"src/JordanWigner/ClusterOperatorEvolutionSet.qs",
55+
"src/JordanWigner/EvolutionSet.qs",
56+
"src/JordanWigner/OptimizedBlockEncoding.qs",
5457
"src/JordanWigner/OptimizedBEOperator.qs",
55-
"src/JordanWigner/StatePreparation.qs",
56-
"src/JordanWigner/Utils.qs"
58+
"src/JordanWigner/StatePreparation.qs"
5759
]
5860
}

library/chemistry/src/Generators.qs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
export GeneratorIndex;
5+
export GeneratorSystem;
6+
export EvolutionGenerator;
7+
export HTermToGenIdx;
8+
export HTermsToGenSys;
9+
export HTermsToGenIdx;
10+
export MultiplexOperationsFromGenerator;
11+
12+
import Std.Math.*;
13+
import 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+
/// ```
41+
struct 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.
52+
struct 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.
62+
struct 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`.
79+
function 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`.
99+
function 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`.
115+
function 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)
148+
operation 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`.
162+
operation 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+
}

0 commit comments

Comments
 (0)