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/StatePreparation.qs

215lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4export PrepareSparseMultiConfigurationalState;
5export PrepareUnitaryCoupledClusterState;
6
7import Std.Arrays.*;
8import Std.Convert.ComplexAsComplexPolar;
9import Std.Convert.IntAsDouble;
10import Std.Math.*;
11import Std.StatePreparation.PreparePureStateD;
12import Std.StatePreparation.ApproximatelyPreparePureStateCP;
13
14import JordanWigner.ClusterOperatorEvolutionSet.JWClusterOperatorEvolutionSet;
15import JordanWigner.ClusterOperatorEvolutionSet.JWClusterOperatorGeneratorSystem;
16import JordanWigner.Data.JWInputState;
17import Trotterization.TrotterSimulationAlgorithm;
18import Generators.EvolutionGenerator;
19
20/// # Summary
21/// Sparse multi-configurational state preparation of trial state by adding excitations
22/// to initial trial state.
23///
24/// # Input
25/// ## initialStatePreparation
26/// Unitary to prepare initial trial state.
27/// ## excitations
28/// Excitations of initial trial state represented by
29/// the amplitude of the excitation and the qubit indices
30/// the excitation acts on.
31/// ## qubits
32/// Qubits of Hamiltonian.
33operation PrepareSparseMultiConfigurationalState(
34 initialStatePreparation : (Qubit[] => Unit),
35 excitations : JWInputState[],
36 qubits : Qubit[]
37) : Unit {
38 let nExcitations = Length(excitations);
39
40 mutable coefficientsSqrtAbs = [];
41 mutable coefficientsNewComplexPolar = [];
42 mutable applyFlips = [];
43
44 for idx in 0..nExcitations - 1 {
45 let amplitudePolar = ComplexAsComplexPolar(excitations[idx].Amplitude);
46 let sqrAbsAmplitude = Sqrt(AbsComplexPolar(amplitudePolar));
47
48 coefficientsSqrtAbs += [sqrAbsAmplitude];
49 coefficientsNewComplexPolar += [new ComplexPolar {
50 Magnitude = sqrAbsAmplitude,
51 Argument = ArgComplexPolar(amplitudePolar)
52 }];
53 applyFlips += [excitations[idx].FermionIndices];
54 }
55
56 let nBitsIndices = Ceiling(Lg(IntAsDouble(nExcitations)));
57
58 mutable success = false;
59 repeat {
60 use auxillary = Qubit[nBitsIndices + 1];
61 use flag = Qubit();
62
63 let arr = Mapped(qubitIndices -> PrepareSingleOccupationsState(qubitIndices, _), applyFlips);
64 let multiplexer = MultiplexerBruteForceFromGenerator(nExcitations, idx -> arr[idx]);
65 ApproximatelyPreparePureStateCP(0.0, coefficientsNewComplexPolar, Reversed(auxillary));
66 multiplexer(auxillary, qubits);
67 Adjoint PreparePureStateD(coefficientsSqrtAbs, Reversed(auxillary));
68 ApplyControlledOnInt(0, X, auxillary, flag);
69
70 // if measurement outcome one we prepared required state
71 let outcome = M(flag);
72 success = outcome == One;
73 ResetAll(auxillary);
74 Reset(flag);
75 } until success
76 fixup {
77 ResetAll(qubits);
78 }
79}
80
81/// # Summary
82/// Unitary coupled-cluster state preparation of trial state
83///
84/// # Input
85/// ## initialStatePreparation
86/// Unitary to prepare initial trial state.
87/// ## qubits
88/// Qubits of Hamiltonian.
89operation PrepareUnitaryCoupledClusterState(
90 initialStatePreparation : (Qubit[] => Unit),
91 clusterOperator : JWInputState[],
92 trotterStepSize : Double,
93 qubits : Qubit[]
94) : Unit {
95 let clusterOperatorGeneratorSystem = JWClusterOperatorGeneratorSystem(clusterOperator);
96 let evolutionGenerator = new EvolutionGenerator {
97 EvolutionSet = JWClusterOperatorEvolutionSet(),
98 System = clusterOperatorGeneratorSystem
99 };
100 let trotterOrder = 1;
101 let simulationAlgorithm = TrotterSimulationAlgorithm(trotterStepSize, trotterOrder);
102 let oracle = simulationAlgorithm(1.0, evolutionGenerator, _);
103 initialStatePreparation(qubits);
104 oracle(qubits);
105}
106
107operation PrepareTrialState(
108 stateData : (Int, JWInputState[]),
109 qubits : Qubit[]
110) : Unit {
111 let (stateType, terms) = stateData;
112
113 // https://github.com/microsoft/QuantumLibraries/blob/main/Chemistry/src/DataModel/TermTypes.cs#L123
114 // State type indexing from FermionHamiltonianStatePrep
115 // public enum StateType
116 //{
117 // Default = 0, Single_Configurational = 1, Sparse_Multi_Configurational = 2, Unitary_Coupled_Cluster = 3
118 //}
119
120 if stateType == 2 {
121 // Sparse_Multi_Configurational
122 if IsEmpty(terms) {
123 // Do nothing, as there are no terms to prepare.
124 } elif Length(terms) == 1 {
125 PrepareSingleOccupationsState(terms[0].FermionIndices, qubits);
126 } else {
127 PrepareSparseMultiConfigurationalState(qs => I(qs[0]), terms, qubits);
128 }
129 } elif stateType == 3 {
130 // Unitary_Coupled_Cluster
131 let nTerms = Length(terms);
132 let trotterStepSize = 1.0;
133
134 // The last term is the reference state.
135 let referenceState = PrepareTrialState((2, [terms[nTerms - 1]]), _);
136
137 PrepareUnitaryCoupledClusterState(referenceState, terms[...nTerms - 2], trotterStepSize, qubits);
138 } else {
139 fail ("Unsupported input state.");
140 }
141}
142
143/// # Summary
144/// Simple state preparation of trial state by occupying spin-orbitals
145///
146/// # Input
147/// ## qubitIndices
148/// Indices of qubits to be occupied by electrons.
149/// ## qubits
150/// Qubits of Hamiltonian.
151operation PrepareSingleOccupationsState(
152 qubitIndices : Int[],
153 qubits : Qubit[]
154) : Unit is Adj + Ctl {
155 ApplyToEachCA(X, Subarray(qubitIndices, qubits));
156}
157
158/// # Summary
159/// Returns a multiply-controlled unitary operation $U$ that applies a
160/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
161///
162/// $U = \sum^{2^n-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
163///
164/// # Input
165/// ## unitaryGenerator
166/// A tuple where the first element `Int` is the number of unitaries $N$,
167/// and the second element `(Int -> ('T => () is Adj + Ctl))`
168/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
169/// operation $V_j$.
170///
171/// # Output
172/// A multiply-controlled unitary operation $U$ that applies unitaries
173/// described by `unitaryGenerator`.
174function MultiplexerBruteForceFromGenerator(
175 unitaryGenerator : (Int, (Int -> (Qubit[] => Unit is Adj + Ctl)))
176) : ((Qubit[], Qubit[]) => Unit is Adj + Ctl) {
177 return MultiplexOperationsBruteForceFromGenerator(unitaryGenerator, _, _);
178}
179
180/// # Summary
181/// Applies multiply-controlled unitary operation $U$ that applies a
182/// unitary $V_j$ when controlled by n-qubit number state $\ket{j}$.
183///
184/// $U = \sum^{N-1}_{j=0}\ket{j}\bra{j}\otimes V_j$.
185///
186/// # Input
187/// ## unitaryGenerator
188/// A tuple where the first element `Int` is the number of unitaries $N$,
189/// and the second element `(Int -> ('T => () is Adj + Ctl))`
190/// is a function that takes an integer $j$ in $[0,N-1]$ and outputs the unitary
191/// operation $V_j$.
192///
193/// ## index
194/// $n$-qubit control register that encodes number states $\ket{j}$ in
195/// little-endian format.
196///
197/// ## target
198/// Generic qubit register that $V_j$ acts on.
199///
200/// # Remarks
201/// `coefficients` will be padded with identity elements if
202/// fewer than $2^n$ are specified. This version is implemented
203/// directly by looping through n-controlled unitary operators.
204operation MultiplexOperationsBruteForceFromGenerator<'T>(
205 unitaryGenerator : (Int, (Int -> ('T => Unit is Adj + Ctl))),
206 index : Qubit[],
207 target : 'T
208) : Unit is Adj + Ctl {
209 let nIndex = Length(index);
210 let nStates = 2^nIndex;
211 let (nUnitaries, unitaryFunction) = unitaryGenerator;
212 for idxOp in 0..MinI(nStates, nUnitaries) - 1 {
213 ApplyControlledOnInt(idxOp, unitaryFunction(idxOp), index, target);
214 }
215}
216