Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chemistry lib: readablility, lints, syntax, tests #2202

Merged
merged 7 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions library/chemistry/qsharp.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@
{
"lint": "needlessParens",
"level": "error"
},
{
"lint": "doubleEquality",
"level": "error"
},
{
"lint": "redundantSemicolons",
"level": "error"
},
{
"lint": "discourageChainAssignment",
"level": "error"
},
{
"lint": "needlessOperation",
"level": "error"
}
],
"files": [
Expand Down
11 changes: 5 additions & 6 deletions library/chemistry/src/JordanWigner/Convenience.qs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ export
QubitizationOracle,
OptimizedQubitizationOracle;

import Std.Convert.IntAsDouble;
import Std.Math.Ceiling;
import Std.Math.Lg;

import JordanWigner.JordanWignerBlockEncoding.JordanWignerBlockEncodingGeneratorSystem;
import JordanWigner.JordanWignerEvolutionSet.JordanWignerFermionEvolutionSet;
import JordanWigner.JordanWignerEvolutionSet.JordanWignerGeneratorSystem;
import JordanWigner.JordanWignerOptimizedBlockEncoding.JordanWignerOptimizedBlockEncoding;
import JordanWigner.JordanWignerOptimizedBlockEncoding.PauliBlockEncoding;
import JordanWigner.JordanWignerOptimizedBlockEncoding.QuantumWalkByQubitization;
import JordanWigner.Utils.JordanWignerEncodingData;
import JordanWigner.Utils.MultiplexOperationsFromGenerator;
import JordanWigner.Utils.TrotterSimulationAlgorithm;
import Std.Convert.IntAsDouble;
import Std.Math.Ceiling;
import Std.Math.Lg;
import Utils.EvolutionGenerator;

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

function QubitizationOracleSeperatedRegisters(jwHamiltonian : JordanWignerEncodingData) : ((Int, Int), (Double, ((Qubit[], Qubit[]) => Unit is Adj + Ctl))) {
let generatorSystem = JordanWignerBlockEncodingGeneratorSystem(jwHamiltonian.Terms);
let (nTerms, genIdxFunction) = generatorSystem!;
let (oneNorm, blockEncodingReflection) = PauliBlockEncoding(generatorSystem);
let nTargetRegisterQubits = jwHamiltonian.NumQubits;
let nCtrlRegisterQubits = Ceiling(Lg(IntAsDouble(nTerms)));
let nCtrlRegisterQubits = Ceiling(Lg(IntAsDouble(generatorSystem.NumEntries)));
return ((nCtrlRegisterQubits, nTargetRegisterQubits), (oneNorm, QuantumWalkByQubitization(blockEncodingReflection)));
}

Expand Down
22 changes: 12 additions & 10 deletions library/chemistry/src/JordanWigner/ConvenienceVQE.qs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export
EstimateEnergyWrapper,
EstimateEnergy;

import Std.Math.Complex;

import JordanWigner.JordanWignerEvolutionSet.JordanWignerGeneratorSystem;
import JordanWigner.JordanWignerVQE.EstimateTermExpectation;
import JordanWigner.JordanWignerVQE.ExpandedCoefficients;
Expand Down Expand Up @@ -36,8 +38,8 @@ operation EstimateEnergyWrapper(jwHamiltonian : (Int, ((Int[], Double[])[], (Int
let (inputState1, inputState2) = inputState;
mutable jwInputState = [];
for entry in inputState2 {
let (amp, idicies) = entry;
jwInputState += [new JordanWignerInputState { Amplitude = amp, FermionIndices = idicies }];
let ((r, i), idicies) = entry;
jwInputState += [new JordanWignerInputState { Amplitude = new Complex { Real = r, Imag = i }, FermionIndices = idicies }];
}
let inputState = (inputState1, jwInputState);
let jwHamiltonian = new JordanWignerEncodingData {
Expand Down Expand Up @@ -67,26 +69,26 @@ operation EstimateEnergy(jwHamiltonian : JordanWignerEncodingData, nSamples : In
// Initialize return value
mutable energy = 0.;

// Unpack information and qubit Hamiltonian terms
let (nQubits, jwTerms, inputState, energyOffset) = jwHamiltonian!;
let nQubits = jwHamiltonian.NumQubits;

// Loop over all qubit Hamiltonian terms
let (nTerms, indexFunction) = (JordanWignerGeneratorSystem(jwTerms))!;
let generatorSystem = JordanWignerGeneratorSystem(jwHamiltonian.Terms);

for idxTerm in 0..nTerms - 1 {
let term = indexFunction(idxTerm);
let ((idxTermType, coeff), idxFermions) = term!;
for idxTerm in 0..generatorSystem.NumEntries - 1 {
let term = generatorSystem.EntryAt(idxTerm);
let (idxTermType, coeff) = term.Term;
let idxFermions = term.Subsystem;
let termType = idxTermType[0];

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

// The private wrapper enables fast emulation during expectation estimation
let inputStateUnitary = PrepareTrialState(inputState, _);
let inputStateUnitary = PrepareTrialState(jwHamiltonian.InputState, _);

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

return energy + energyOffset;
return energy + jwHamiltonian.EnergyOffset;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

export JordanWignerBlockEncodingGeneratorSystem;

import Std.Arrays.IndexRange;

import JordanWigner.Utils.JWOptimizedHTerms;
import JordanWigner.Utils.RangeAsIntArray;
import Std.Arrays.IndexRange;
import Utils.GeneratorIndex;
import Utils.GeneratorSystem;
import Utils.HTermToGenIdx;
Expand Down Expand Up @@ -164,7 +165,10 @@ function V0123TermToPauliGenIdx(term : GeneratorIndex) : GeneratorIndex[] {
/// # Output
/// Representation of Hamiltonian as `GeneratorSystem`.
function JordanWignerBlockEncodingGeneratorSystem(data : JWOptimizedHTerms) : GeneratorSystem {
let (ZData, ZZData, PQandPQQRData, h0123Data) = data!;
let ZData = data.HTerm0;
let ZZData = data.HTerm1;
let PQandPQQRData = data.HTerm2;
let h0123Data = data.HTerm3;
mutable genIdxes = Repeated(
new GeneratorIndex { Term = ([0], [0.0]), Subsystem = [0] },
((Length(ZData) + Length(ZZData)) + 2 * Length(PQandPQQRData)) + 8 * Length(h0123Data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ export
JordanWignerClusterOperatorEvolutionSet,
JordanWignerClusterOperatorGeneratorSystem;

import JordanWigner.Utils.JordanWignerInputState;
import Std.Arrays.IndexRange;
import Std.Math.Max;
import Std.Math.Min;

import JordanWigner.Utils.JordanWignerInputState;
import Utils.GeneratorIndex;
import Utils.GeneratorSystem;

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

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

// Identical to `ComputeJordanWignerPauliZString`, except that some
// specified elements are substituted.
function ComputeJordanWignerPauliString(nFermions : Int, idxFermions : Int[], pauliReplacements : Pauli[]) : Pauli[] {
function ComputeJordanWignerPauliString(
nFermions : Int,
idxFermions : Int[],
pauliReplacements : Pauli[]
) : Pauli[] {

mutable pauliString = ComputeJordanWignerPauliZString(nFermions, idxFermions);

for idx in IndexRange(idxFermions) {
Expand All @@ -89,8 +96,14 @@ function ComputeJordanWignerPauliString(nFermions : Int, idxFermions : Int[], pa
/// Duration of time-evolution.
/// ## qubits
/// Qubits of Hamiltonian.
operation ApplyJordanWignerClusterOperatorPQTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, coeff), idxFermions) = term!;
operation ApplyJordanWignerClusterOperatorPQTerm(
term : GeneratorIndex,
stepSize : Double,
qubits : Qubit[]
) : Unit is Adj + Ctl {

let (_, coeff) = term.Term;
let idxFermions = term.Subsystem;
let p = idxFermions[0];
let q = idxFermions[1];
if p == q {
Expand All @@ -117,8 +130,14 @@ operation ApplyJordanWignerClusterOperatorPQTerm(term : GeneratorIndex, stepSize
/// Duration of time-evolution.
/// ## qubits
/// Qubits of Hamiltonian.
operation ApplyJordanWignerClusterOperatorPQRSTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, coeff), idxFermions) = term!;
operation ApplyJordanWignerClusterOperatorPQRSTerm(
term : GeneratorIndex,
stepSize : Double,
qubits : Qubit[]
) : Unit is Adj + Ctl {

let (_, coeff) = term.Term;
let idxFermions = term.Subsystem;
let p = idxFermions[0];
let q = idxFermions[1];
let r = idxFermions[2];
Expand Down Expand Up @@ -146,8 +165,8 @@ function JordanWignerClusterOperatorPQRSTermSigns(indices : Int[]) : (Int[], Dou
let q = indices[1];
let r = indices[2];
let s = indices[3];
mutable sorted = [0, size = 4];
mutable signs = [0.0, size = 8];
mutable sorted = [0, 0, 0, 0];
mutable signs = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
mutable sign = 1.0;

if (p > q) {
Expand Down Expand Up @@ -199,12 +218,18 @@ function JordanWignerClusterOperatorPQRSTermSigns(indices : Int[]) : (Int[], Dou
///
/// # Output
/// Representation of Hamiltonian as `GeneratorSystem`.
function JordanWignerClusterOperatorGeneratorSystem(data : JordanWignerInputState[]) : GeneratorSystem {
new GeneratorSystem { NumEntries = Length(data), EntryAt = JordanWignerStateAsGeneratorIndex(data, _) }
function JordanWignerClusterOperatorGeneratorSystem(
data : JordanWignerInputState[]
) : GeneratorSystem {
new GeneratorSystem {
NumEntries = Length(data),
EntryAt = JordanWignerStateAsGeneratorIndex(data, _)
}
}

function JordanWignerStateAsGeneratorIndex(data : JordanWignerInputState[], idx : Int) : GeneratorIndex {
let ((real, imaginary), idxFermions) = data[idx]!;
let real = data[idx].Amplitude.Real;
let idxFermions = data[idx].FermionIndices;

if Length(idxFermions) == 2 {
// PQ term
Expand All @@ -229,8 +254,13 @@ function JordanWignerStateAsGeneratorIndex(data : JordanWignerInputState[], idx
/// Dummy variable to match signature of simulation algorithms.
/// ## qubits
/// Register acted upon by time-evolution operator.
operation JordanWignerClusterOperatorImpl(generatorIndex : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, idxDoubles), idxFermions) = generatorIndex!;
operation JordanWignerClusterOperatorImpl(
generatorIndex : GeneratorIndex,
stepSize : Double,
qubits : Qubit[]
) : Unit is Adj + Ctl {

let (idxTermType, _) = generatorIndex.Term;
let termType = idxTermType[0];

if termType == 0 {
Expand Down
19 changes: 13 additions & 6 deletions library/chemistry/src/JordanWigner/JordanWignerEvolutionSet.qs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ export
JordanWignerGeneratorSystem,
JordanWignerFermionEvolutionSet;

import JordanWigner.Utils.JWOptimizedHTerms;
import Std.Arrays.IndexRange;
import Std.Arrays.Subarray;

import JordanWigner.Utils.JWOptimizedHTerms;
import Utils.GeneratorIndex;
import Utils.GeneratorSystem;
import Utils.HTermsToGenSys;
Expand Down Expand Up @@ -77,7 +78,8 @@ operation ApplyJordanWignerZZTerm(term : GeneratorIndex, stepSize : Double, qubi
/// ## qubits
/// Qubits of Hamiltonian.
operation ApplyJordanWignerPQTerm(term : GeneratorIndex, stepSize : Double, extraParityQubits : Qubit[], qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, coeff), idxFermions) = term!;
let (_, coeff) = term.Term;
let idxFermions = term.Subsystem;
let angle = (1.0 * coeff[0]) * stepSize;
let qubitsPQ = Subarray(idxFermions[0..1], qubits);
let qubitsJW = qubits[idxFermions[0] + 1..idxFermions[1] - 1];
Expand All @@ -101,7 +103,8 @@ operation ApplyJordanWignerPQTerm(term : GeneratorIndex, stepSize : Double, extr
/// ## qubits
/// Qubits of Hamiltonian.
operation ApplyJordanWignerPQandPQQRTerm(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, coeff), idxFermions) = term!;
let (idxTermType, coeff) = term.Term;
let idxFermions = term.Subsystem;
let angle = (1.0 * coeff[0]) * stepSize;
let qubitQidx = idxFermions[1];

Expand Down Expand Up @@ -138,7 +141,8 @@ operation ApplyJordanWignerPQandPQQRTerm(term : GeneratorIndex, stepSize : Doubl
/// ## qubits
/// Qubits to apply the given term to.
operation ApplyJordanWigner0123Term(term : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, v0123), idxFermions) = term!;
let (idxTermType, v0123) = term.Term;
let idxFermions = term.Subsystem;
let angle = stepSize;
let qubitsPQ = Subarray(idxFermions[0..1], qubits);
let qubitsRS = Subarray(idxFermions[2..3], qubits);
Expand Down Expand Up @@ -166,7 +170,10 @@ operation ApplyJordanWigner0123Term(term : GeneratorIndex, stepSize : Double, qu
/// # Output
/// Representation of Hamiltonian as `GeneratorSystem`.
function JordanWignerGeneratorSystem(data : JWOptimizedHTerms) : GeneratorSystem {
let (ZData, ZZData, PQandPQQRData, h0123Data) = data!;
let ZData = data.HTerm0;
let ZZData = data.HTerm1;
let PQandPQQRData = data.HTerm2;
let h0123Data = data.HTerm3;
let ZGenSys = HTermsToGenSys(ZData, [0]);
let ZZGenSys = HTermsToGenSys(ZZData, [1]);
let PQandPQQRGenSys = HTermsToGenSys(PQandPQQRData, [2]);
Expand Down Expand Up @@ -214,7 +221,7 @@ function AddGeneratorSystems(generatorSystemA : GeneratorSystem, generatorSystem
/// ## qubits
/// Register acted upon by time-evolution operator.
operation JordanWignerFermionImpl(generatorIndex : GeneratorIndex, stepSize : Double, qubits : Qubit[]) : Unit is Adj + Ctl {
let ((idxTermType, idxDoubles), idxFermions) = generatorIndex!;
let (idxTermType, idxDoubles) = generatorIndex.Term;
let termType = idxTermType[0];

if (termType == 0) {
Expand Down
Loading