microsoft/qdk
Publicmirrored from https://github.com/microsoft/qdkAvailable
library/chemistry/src/JordanWigner/StatePreparation.qs
215lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | export PrepareSparseMultiConfigurationalState; |
| 5 | export PrepareUnitaryCoupledClusterState; |
| 6 | |
| 7 | import Std.Arrays.*; |
| 8 | import Std.Convert.ComplexAsComplexPolar; |
| 9 | import Std.Convert.IntAsDouble; |
| 10 | import Std.Math.*; |
| 11 | import Std.StatePreparation.PreparePureStateD; |
| 12 | import Std.StatePreparation.ApproximatelyPreparePureStateCP; |
| 13 | |
| 14 | import JordanWigner.ClusterOperatorEvolutionSet.JWClusterOperatorEvolutionSet; |
| 15 | import JordanWigner.ClusterOperatorEvolutionSet.JWClusterOperatorGeneratorSystem; |
| 16 | import JordanWigner.Data.JWInputState; |
| 17 | import Trotterization.TrotterSimulationAlgorithm; |
| 18 | import 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. |
| 33 | operation 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. |
| 89 | operation 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 | |
| 107 | operation 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. |
| 151 | operation 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`. |
| 174 | function 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. |
| 204 | operation 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 | |