Skip to content

Commit 015fb3f

Browse files
DmitryVasilevskyDmitry Vasilevsky
andauthored
Chemistry lib: readablility, lints, syntax, tests (#2202)
This change updates chemistry library: - Removes old sysntax such as a! and [x, size=5] - Reduced use of w/= where possible - Makes long argument lists more readable - Fixes error in comments - Updates pairs of double representing a complex number to use complex type - Adds a few unit tests No renames yet. --------- Co-authored-by: Dmitry Vasilevsky <[email protected]>
1 parent 882cd6e commit 015fb3f

13 files changed

+397
-153
lines changed

library/chemistry/qsharp.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@
2323
{
2424
"lint": "needlessParens",
2525
"level": "error"
26+
},
27+
{
28+
"lint": "doubleEquality",
29+
"level": "error"
30+
},
31+
{
32+
"lint": "redundantSemicolons",
33+
"level": "error"
34+
},
35+
{
36+
"lint": "discourageChainAssignment",
37+
"level": "error"
38+
},
39+
{
40+
"lint": "needlessOperation",
41+
"level": "error"
2642
}
2743
],
2844
"files": [

library/chemistry/src/JordanWigner/Convenience.qs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ export
66
QubitizationOracle,
77
OptimizedQubitizationOracle;
88

9+
import Std.Convert.IntAsDouble;
10+
import Std.Math.Ceiling;
11+
import Std.Math.Lg;
12+
913
import JordanWigner.JordanWignerBlockEncoding.JordanWignerBlockEncodingGeneratorSystem;
1014
import JordanWigner.JordanWignerEvolutionSet.JordanWignerFermionEvolutionSet;
1115
import JordanWigner.JordanWignerEvolutionSet.JordanWignerGeneratorSystem;
1216
import JordanWigner.JordanWignerOptimizedBlockEncoding.JordanWignerOptimizedBlockEncoding;
1317
import JordanWigner.JordanWignerOptimizedBlockEncoding.PauliBlockEncoding;
1418
import JordanWigner.JordanWignerOptimizedBlockEncoding.QuantumWalkByQubitization;
1519
import JordanWigner.Utils.JordanWignerEncodingData;
16-
import JordanWigner.Utils.MultiplexOperationsFromGenerator;
1720
import JordanWigner.Utils.TrotterSimulationAlgorithm;
18-
import Std.Convert.IntAsDouble;
19-
import Std.Math.Ceiling;
20-
import Std.Math.Lg;
2121
import Utils.EvolutionGenerator;
2222

2323
// Convenience functions for performing simulation.
@@ -50,10 +50,9 @@ function TrotterStepOracle(jwHamiltonian : JordanWignerEncodingData, trotterStep
5050

5151
function QubitizationOracleSeperatedRegisters(jwHamiltonian : JordanWignerEncodingData) : ((Int, Int), (Double, ((Qubit[], Qubit[]) => Unit is Adj + Ctl))) {
5252
let generatorSystem = JordanWignerBlockEncodingGeneratorSystem(jwHamiltonian.Terms);
53-
let (nTerms, genIdxFunction) = generatorSystem!;
5453
let (oneNorm, blockEncodingReflection) = PauliBlockEncoding(generatorSystem);
5554
let nTargetRegisterQubits = jwHamiltonian.NumQubits;
56-
let nCtrlRegisterQubits = Ceiling(Lg(IntAsDouble(nTerms)));
55+
let nCtrlRegisterQubits = Ceiling(Lg(IntAsDouble(generatorSystem.NumEntries)));
5756
return ((nCtrlRegisterQubits, nTargetRegisterQubits), (oneNorm, QuantumWalkByQubitization(blockEncodingReflection)));
5857
}
5958

library/chemistry/src/JordanWigner/ConvenienceVQE.qs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export
55
EstimateEnergyWrapper,
66
EstimateEnergy;
77

8+
import Std.Math.Complex;
9+
810
import JordanWigner.JordanWignerEvolutionSet.JordanWignerGeneratorSystem;
911
import JordanWigner.JordanWignerVQE.EstimateTermExpectation;
1012
import JordanWigner.JordanWignerVQE.ExpandedCoefficients;
@@ -36,8 +38,8 @@ operation EstimateEnergyWrapper(jwHamiltonian : (Int, ((Int[], Double[])[], (Int
3638
let (inputState1, inputState2) = inputState;
3739
mutable jwInputState = [];
3840
for entry in inputState2 {
39-
let (amp, idicies) = entry;
40-
jwInputState += [new JordanWignerInputState { Amplitude = amp, FermionIndices = idicies }];
41+
let ((r, i), idicies) = entry;
42+
jwInputState += [new JordanWignerInputState { Amplitude = new Complex { Real = r, Imag = i }, FermionIndices = idicies }];
4143
}
4244
let inputState = (inputState1, jwInputState);
4345
let jwHamiltonian = new JordanWignerEncodingData {
@@ -67,26 +69,26 @@ operation EstimateEnergy(jwHamiltonian : JordanWignerEncodingData, nSamples : In
6769
// Initialize return value
6870
mutable energy = 0.;
6971

70-
// Unpack information and qubit Hamiltonian terms
71-
let (nQubits, jwTerms, inputState, energyOffset) = jwHamiltonian!;
72+
let nQubits = jwHamiltonian.NumQubits;
7273

7374
// Loop over all qubit Hamiltonian terms
74-
let (nTerms, indexFunction) = (JordanWignerGeneratorSystem(jwTerms))!;
75+
let generatorSystem = JordanWignerGeneratorSystem(jwHamiltonian.Terms);
7576

76-
for idxTerm in 0..nTerms - 1 {
77-
let term = indexFunction(idxTerm);
78-
let ((idxTermType, coeff), idxFermions) = term!;
77+
for idxTerm in 0..generatorSystem.NumEntries - 1 {
78+
let term = generatorSystem.EntryAt(idxTerm);
79+
let (idxTermType, coeff) = term.Term;
80+
let idxFermions = term.Subsystem;
7981
let termType = idxTermType[0];
8082

8183
let ops = MeasurementOperators(nQubits, idxFermions, termType);
8284
let coeffs = ExpandedCoefficients(coeff, termType);
8385

8486
// The private wrapper enables fast emulation during expectation estimation
85-
let inputStateUnitary = PrepareTrialState(inputState, _);
87+
let inputStateUnitary = PrepareTrialState(jwHamiltonian.InputState, _);
8688

8789
let jwTermEnergy = EstimateTermExpectation(inputStateUnitary, ops, coeffs, nQubits, nSamples);
8890
energy += jwTermEnergy;
8991
}
9092

91-
return energy + energyOffset;
93+
return energy + jwHamiltonian.EnergyOffset;
9294
}

library/chemistry/src/JordanWigner/JordanWignerBlockEncoding.qs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
export JordanWignerBlockEncodingGeneratorSystem;
55

6+
import Std.Arrays.IndexRange;
7+
68
import JordanWigner.Utils.JWOptimizedHTerms;
79
import JordanWigner.Utils.RangeAsIntArray;
8-
import Std.Arrays.IndexRange;
910
import Utils.GeneratorIndex;
1011
import Utils.GeneratorSystem;
1112
import Utils.HTermToGenIdx;
@@ -164,7 +165,10 @@ function V0123TermToPauliGenIdx(term : GeneratorIndex) : GeneratorIndex[] {
164165
/// # Output
165166
/// Representation of Hamiltonian as `GeneratorSystem`.
166167
function JordanWignerBlockEncodingGeneratorSystem(data : JWOptimizedHTerms) : GeneratorSystem {
167-
let (ZData, ZZData, PQandPQQRData, h0123Data) = data!;
168+
let ZData = data.HTerm0;
169+
let ZZData = data.HTerm1;
170+
let PQandPQQRData = data.HTerm2;
171+
let h0123Data = data.HTerm3;
168172
mutable genIdxes = Repeated(
169173
new GeneratorIndex { Term = ([0], [0.0]), Subsystem = [0] },
170174
((Length(ZData) + Length(ZZData)) + 2 * Length(PQandPQQRData)) + 8 * Length(h0123Data)

library/chemistry/src/JordanWigner/JordanWignerClusterOperatorEvolutionSet.qs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ export
55
JordanWignerClusterOperatorEvolutionSet,
66
JordanWignerClusterOperatorGeneratorSystem;
77

8-
import JordanWigner.Utils.JordanWignerInputState;
98
import Std.Arrays.IndexRange;
109
import Std.Math.Max;
1110
import Std.Math.Min;
11+
12+
import JordanWigner.Utils.JordanWignerInputState;
1213
import Utils.GeneratorIndex;
1314
import Utils.GeneratorSystem;
1415

@@ -28,19 +29,20 @@ import Utils.GeneratorSystem;
2829
///
2930
/// # Example
3031
/// ```qsharp
31-
/// let bitString = ComputeJordanWignerBitString(6, [0,1,2,6]) ;
32-
/// // bitString is [false, false, false ,true, true, true, false].
32+
/// let bitString = ComputeJordanWignerBitString(5, [0, 3]) ;
33+
/// // bitString is [false, true, true, false, false].
3334
/// ```
3435
function ComputeJordanWignerBitString(nFermions : Int, idxFermions : Int[]) : Bool[] {
3536
if Length(idxFermions) % 2 != 0 {
3637
fail $"ComputeJordanWignerString failed. `idxFermions` must contain an even number of terms.";
3738
}
3839

39-
mutable zString = [false, size = nFermions];
40+
mutable zString = Repeated(false, nFermions);
4041
for fermionIdx in idxFermions {
4142
if fermionIdx >= nFermions {
4243
fail $"ComputeJordanWignerString failed. fermionIdx {fermionIdx} out of range.";
4344
}
45+
// NOTE: This could be optimized
4446
for idx in 0..fermionIdx {
4547
zString w/= idx <- not zString[idx];
4648
}
@@ -67,7 +69,12 @@ function ComputeJordanWignerPauliZString(nFermions : Int, idxFermions : Int[]) :
6769

6870
// Identical to `ComputeJordanWignerPauliZString`, except that some
6971
// specified elements are substituted.
70-
function ComputeJordanWignerPauliString(nFermions : Int, idxFermions : Int[], pauliReplacements : Pauli[]) : Pauli[] {
72+
function ComputeJordanWignerPauliString(
73+
nFermions : Int,
74+
idxFermions : Int[],
75+
pauliReplacements : Pauli[]
76+
) : Pauli[] {
77+
7178
mutable pauliString = ComputeJordanWignerPauliZString(nFermions, idxFermions);
7279

7380
for idx in IndexRange(idxFermions) {
@@ -89,8 +96,14 @@ function ComputeJordanWignerPauliString(nFermions : Int, idxFermions : Int[], pa
8996
/// Duration of time-evolution.
9097
/// ## qubits
9198
/// Qubits of Hamiltonian.
92-
operation ApplyJordanWignerClusterOperatorPQTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
93-
let ((idxTermType, coeff), idxFermions) = term!;
99+
operation ApplyJordanWignerClusterOperatorPQTerm(
100+
term : GeneratorIndex,
101+
stepSize : Double,
102+
qubits : Qubit[]
103+
) : Unit is Adj + Ctl {
104+
105+
let (_, coeff) = term.Term;
106+
let idxFermions = term.Subsystem;
94107
let p = idxFermions[0];
95108
let q = idxFermions[1];
96109
if p == q {
@@ -117,8 +130,14 @@ operation ApplyJordanWignerClusterOperatorPQTerm(term : GeneratorIndex, stepSize
117130
/// Duration of time-evolution.
118131
/// ## qubits
119132
/// Qubits of Hamiltonian.
120-
operation ApplyJordanWignerClusterOperatorPQRSTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
121-
let ((idxTermType, coeff), idxFermions) = term!;
133+
operation ApplyJordanWignerClusterOperatorPQRSTerm(
134+
term : GeneratorIndex,
135+
stepSize : Double,
136+
qubits : Qubit[]
137+
) : Unit is Adj + Ctl {
138+
139+
let (_, coeff) = term.Term;
140+
let idxFermions = term.Subsystem;
122141
let p = idxFermions[0];
123142
let q = idxFermions[1];
124143
let r = idxFermions[2];
@@ -146,8 +165,8 @@ function JordanWignerClusterOperatorPQRSTermSigns(indices : Int[]) : (Int[], Dou
146165
let q = indices[1];
147166
let r = indices[2];
148167
let s = indices[3];
149-
mutable sorted = [0, size = 4];
150-
mutable signs = [0.0, size = 8];
168+
mutable sorted = [0, 0, 0, 0];
169+
mutable signs = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
151170
mutable sign = 1.0;
152171

153172
if (p > q) {
@@ -199,12 +218,18 @@ function JordanWignerClusterOperatorPQRSTermSigns(indices : Int[]) : (Int[], Dou
199218
///
200219
/// # Output
201220
/// Representation of Hamiltonian as `GeneratorSystem`.
202-
function JordanWignerClusterOperatorGeneratorSystem(data : JordanWignerInputState[]) : GeneratorSystem {
203-
new GeneratorSystem { NumEntries = Length(data), EntryAt = JordanWignerStateAsGeneratorIndex(data, _) }
221+
function JordanWignerClusterOperatorGeneratorSystem(
222+
data : JordanWignerInputState[]
223+
) : GeneratorSystem {
224+
new GeneratorSystem {
225+
NumEntries = Length(data),
226+
EntryAt = JordanWignerStateAsGeneratorIndex(data, _)
227+
}
204228
}
205229

206230
function JordanWignerStateAsGeneratorIndex(data : JordanWignerInputState[], idx : Int) : GeneratorIndex {
207-
let ((real, imaginary), idxFermions) = data[idx]!;
231+
let real = data[idx].Amplitude.Real;
232+
let idxFermions = data[idx].FermionIndices;
208233

209234
if Length(idxFermions) == 2 {
210235
// PQ term
@@ -229,8 +254,13 @@ function JordanWignerStateAsGeneratorIndex(data : JordanWignerInputState[], idx
229254
/// Dummy variable to match signature of simulation algorithms.
230255
/// ## qubits
231256
/// Register acted upon by time-evolution operator.
232-
operation JordanWignerClusterOperatorImpl(generatorIndex : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
233-
let ((idxTermType, idxDoubles), idxFermions) = generatorIndex!;
257+
operation JordanWignerClusterOperatorImpl(
258+
generatorIndex : GeneratorIndex,
259+
stepSize : Double,
260+
qubits : Qubit[]
261+
) : Unit is Adj + Ctl {
262+
263+
let (idxTermType, _) = generatorIndex.Term;
234264
let termType = idxTermType[0];
235265

236266
if termType == 0 {

library/chemistry/src/JordanWigner/JordanWignerEvolutionSet.qs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ export
55
JordanWignerGeneratorSystem,
66
JordanWignerFermionEvolutionSet;
77

8-
import JordanWigner.Utils.JWOptimizedHTerms;
98
import Std.Arrays.IndexRange;
109
import Std.Arrays.Subarray;
10+
11+
import JordanWigner.Utils.JWOptimizedHTerms;
1112
import Utils.GeneratorIndex;
1213
import Utils.GeneratorSystem;
1314
import Utils.HTermsToGenSys;
@@ -77,7 +78,8 @@ operation ApplyJordanWignerZZTerm(term : GeneratorIndex, stepSize : Double, qubi
7778
/// ## qubits
7879
/// Qubits of Hamiltonian.
7980
operation ApplyJordanWignerPQTerm(term : GeneratorIndex, stepSize : Double, extraParityQubits : Qubit[], qubits : Qubit[]) : Unit is Adj + Ctl {
80-
let ((idxTermType, coeff), idxFermions) = term!;
81+
let (_, coeff) = term.Term;
82+
let idxFermions = term.Subsystem;
8183
let angle = (1.0 * coeff[0]) * stepSize;
8284
let qubitsPQ = Subarray(idxFermions[0..1], qubits);
8385
let qubitsJW = qubits[idxFermions[0] + 1..idxFermions[1] - 1];
@@ -101,7 +103,8 @@ operation ApplyJordanWignerPQTerm(term : GeneratorIndex, stepSize : Double, extr
101103
/// ## qubits
102104
/// Qubits of Hamiltonian.
103105
operation ApplyJordanWignerPQandPQQRTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
104-
let ((idxTermType, coeff), idxFermions) = term!;
106+
let (idxTermType, coeff) = term.Term;
107+
let idxFermions = term.Subsystem;
105108
let angle = (1.0 * coeff[0]) * stepSize;
106109
let qubitQidx = idxFermions[1];
107110

@@ -138,7 +141,8 @@ operation ApplyJordanWignerPQandPQQRTerm(term : GeneratorIndex, stepSize : Doubl
138141
/// ## qubits
139142
/// Qubits to apply the given term to.
140143
operation ApplyJordanWigner0123Term(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
141-
let ((idxTermType, v0123), idxFermions) = term!;
144+
let (idxTermType, v0123) = term.Term;
145+
let idxFermions = term.Subsystem;
142146
let angle = stepSize;
143147
let qubitsPQ = Subarray(idxFermions[0..1], qubits);
144148
let qubitsRS = Subarray(idxFermions[2..3], qubits);
@@ -166,7 +170,10 @@ operation ApplyJordanWigner0123Term(term : GeneratorIndex, stepSize : Double, qu
166170
/// # Output
167171
/// Representation of Hamiltonian as `GeneratorSystem`.
168172
function JordanWignerGeneratorSystem(data : JWOptimizedHTerms) : GeneratorSystem {
169-
let (ZData, ZZData, PQandPQQRData, h0123Data) = data!;
173+
let ZData = data.HTerm0;
174+
let ZZData = data.HTerm1;
175+
let PQandPQQRData = data.HTerm2;
176+
let h0123Data = data.HTerm3;
170177
let ZGenSys = HTermsToGenSys(ZData, [0]);
171178
let ZZGenSys = HTermsToGenSys(ZZData, [1]);
172179
let PQandPQQRGenSys = HTermsToGenSys(PQandPQQRData, [2]);
@@ -214,7 +221,7 @@ function AddGeneratorSystems(generatorSystemA : GeneratorSystem, generatorSystem
214221
/// ## qubits
215222
/// Register acted upon by time-evolution operator.
216223
operation JordanWignerFermionImpl(generatorIndex : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
217-
let ((idxTermType, idxDoubles), idxFermions) = generatorIndex!;
224+
let (idxTermType, idxDoubles) = generatorIndex.Term;
218225
let termType = idxTermType[0];
219226

220227
if (termType == 0) {

0 commit comments

Comments
 (0)