/// <summary> /// Updates an instance of <see cref="FermionHamiltonian"/> /// with all spin-orbitals from described by a sequence of two-body orbital integrals. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="hpqTerms">Sequence of two-body orbital integrals.</param> /// <param name="hamiltonian">Fermion Hamiltonian to be updated.</param> public void CreateTwoBodySpinOrbitalTerms(OrbitalIntegral orbitalIntegral) { // One-electron orbital integral symmetries // ij = ji var pqSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals(); var coefficient = orbitalIntegral.Coefficient; foreach (var pq in pqSpinOrbitals) { var p = pq[0]; var q = pq[1]; var pInt = p.ToInt(); var qInt = q.ToInt(); if (pInt == qInt) { AddFermionTerm(FermionTermType.Common.PPTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 0 }, SpinOrbitalIndices = pq, coeff = coefficient }); } else if (pInt < qInt) { AddFermionTerm(FermionTermType.Common.PQTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 0 }, SpinOrbitalIndices = pq, coeff = 2.0 * coefficient }); } } }
/// <summary> /// Method for adding to a <see cref="FermionHamiltonian"/>. /// all <see cref="FermionTerm"/> generalted by all all symmetries of /// <see cref="OrbitalIntegral.EnumerateOrbitalSymmetries"/> and /// <see cref="OrbitalIntegral.EnumerateSpinOrbitals"/>. /// </summary> /// <param name="termType"><see cref="OrbitalIntegral"/> representing terms to be added.</param> public void AddFermionTerm(OrbitalIntegral orbitalIntgral) { if (orbitalIntgral.Length() == 2) { CreateTwoBodySpinOrbitalTerms(orbitalIntgral); } else if (orbitalIntgral.Length() == 4) { CreateFourBodySpinOrbitalTerms(orbitalIntgral); } else { throw new System.NotImplementedException(); } }
/// <summary> /// Updates an instance of <see cref="FermionHamiltonian"/> /// with all spin-orbitals from described by a sequence of four-body orbital integrals. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="rawPQRSTerms">Sequence of four-body orbital integrals.</param> /// <param name="hamiltonian">Fermion Hamiltonian to be updated.</param> public void CreateFourBodySpinOrbitalTerms(OrbitalIntegral orbitalIntegral) { // Two-electron orbital integral symmetries // ijkl = lkji = jilk = klij = ikjl = ljki = kilj = jlik. var pqrsSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals(); var coefficient = orbitalIntegral.Coefficient; // We only need to see one of these. // Now iterate over pqrsArray foreach (var pqrs in pqrsSpinOrbitals) { var p = pqrs[0]; var q = pqrs[1]; var r = pqrs[2]; var s = pqrs[3]; var pInt = p.ToInt(); var qInt = q.ToInt(); var rInt = r.ToInt(); var sInt = s.ToInt(); // Only consider terms on the lower diagonal due to Hermitian symmetry. // For terms with two different orbital indices, possibilities are // PPQQ (QQ = 0), PQPQ, QPPQ (p<q), PQQP, QPQP (p<q), QQPP (PP=0) // Hence, if we only count PQQP, and PQPQ, we need to double the coefficient. // iU jU jU iU | iU jD jD iD | iD jU jU iD | iD jD jD iD if (pInt == sInt && qInt == rInt && pInt < qInt) { // PQQP AddFermionTerm(FermionTermType.Common.PQQPTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, r, s }, coeff = 1.0 * coefficient }); } else if (pInt == rInt && qInt == sInt && pInt < qInt) { // iU jU iU jU | iD jD iD jD // PQPQ AddFermionTerm(FermionTermType.Common.PQQPTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, s, r }, coeff = -1.0 * coefficient }); } else if (qInt == rInt && pInt < sInt && rInt != sInt && pInt != qInt) { // PQQR // For any distinct pqr, [i;j;j;k] generates PQQR ~ RQQP ~ QPRQ ~ QRPQ. We only need to record one. if (rInt < sInt) { if (pInt < qInt) { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, s, r }, coeff = -2.0 * coefficient }); } else { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { q, p, s, r }, coeff = 2.0 * coefficient }); } } else { if (pInt < qInt) { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, r, s }, coeff = 2.0 * coefficient }); } else { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { q, p, r, s }, coeff = -2.0 * coefficient }); } } } else if (qInt == sInt && pInt < rInt && rInt != sInt && pInt != sInt) { // PQRQ // For any distinct pqr, [i;j;k;j] generates {p, q, r, q}, {q, r, q, p}, {q, p, q, r}, {r, q, p, q}. We only need to record one. if (pInt < qInt) { if (rInt > qInt) { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, r, s }, coeff = 2.0 * coefficient }); } else { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, s, r }, coeff = -2.0 * coefficient }); } } else { AddFermionTerm(FermionTermType.Common.PQQRTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { q, p, r, s }, coeff = -2.0 * coefficient }); } } else if (pInt < qInt && pInt < rInt && pInt < sInt && qInt != rInt && qInt != sInt && rInt != sInt) { // PQRS // For any distinct pqrs, [i;j;k;l] generates // {{p, q, r, s}<->{s, r, q, p}<->{q, p, s, r}<->{r, s, p, q}, // {1,2,3,4}<->{4,3,2,1}<->{2,1,4,3}<->{3,4,1,2} // {p, r, q, s}<->{s, q, r, p}<->{r, p, s, q}<->{q, s, p, r}} // 1324, 4231, 3142, 2413 if (rInt < sInt) { AddFermionTerm(FermionTermType.Common.PQRSTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, s, r }, coeff = -2.0 * coefficient }); } else { AddFermionTerm(FermionTermType.Common.PQRSTermType, new FermionTerm { CreationAnnihilationIndices = new Int64[] { 1, 1, 0, 0 }, SpinOrbitalIndices = new SpinOrbital[] { p, q, r, s }, coeff = 2.0 * coefficient }); } } } }
/// <summary> /// Loads a Hamiltonian from integral data represented /// in LIQ𝑈𝑖|⟩ format. /// Please see the <a href="https://stationq.github.io/Liquid/docs/LIQUiD.pdf"> /// LIQ𝑈𝑖|⟩ documentation</a> for further details about the /// format parsed by this method. /// </summary> /// <param name="lines">Sequence of text describing terms of Hamiltonian.</param> /// <returns> /// An instance of <see cref="FermionHamiltonian"/> representing the /// data contained in <paramref name="lines"/>. /// </returns> public static FermionHamiltonian LoadFromLiquid(string line) { var regexMiscellaneous = new Regex(@"((info=(?<info>[^\s]*)))"); var regexnuc = new Regex(@"nuc=(?<nuc>-?\s*\d*.\d*)"); var regexPQ = new Regex(@"(^|\s+)(?<p>\d+),(?<q>\d+)\D*=\s*(?<coeff>-?\s*\d*.\d*)e?(?<exponent>-?\d*)"); var regexPQRS = new Regex(@"(^|\s+)(?<p>\d+)\D+(?<q>\d+)\D+(?<r>\d+)\D+(?<s>\d+)\D*=\s*(?<coeff>-?\s*\d*.\d*)e?(?<exponent>-?\d*)"); Double coulombRepulsion = 0.0; var fileHIJTerms = new Dictionary <Int64[], Double>(new Extensions.IntArrayIEqualityComparer()); var fileHIJKLTerms = new Dictionary <Int64[], Double>(new Extensions.IntArrayIEqualityComparer()); var hamiltonian = new FermionHamiltonian(); var nOrbitals = 0L; Match stringMisc = regexMiscellaneous.Match(line); if (stringMisc.Success) { hamiltonian.MiscellaneousInformation = stringMisc.Groups["info"].ToString(); } Match stringnuc = regexnuc.Match(line); if (stringnuc.Success) { hamiltonian.EnergyOffset = Double.Parse(stringnuc.Groups["nuc"].ToString()); } foreach (Match stringPQ in regexPQ.Matches(line)) { if (stringPQ.Success) { var p = Int64.Parse(stringPQ.Groups["p"].ToString()); var q = Int64.Parse(stringPQ.Groups["q"].ToString()); var coeff = Double.Parse(stringPQ.Groups["coeff"].ToString()); var exponentString = stringPQ.Groups["exponent"].ToString(); var exponent = 0.0; if (exponentString != "") { exponent = Double.Parse(stringPQ.Groups["exponent"].ToString()); } nOrbitals = new long[] { nOrbitals, p + 1, q + 1 }.Max(); var orbitalIntegral = new OrbitalIntegral(new Int64[] { p, q }, coeff * (10.0).Pow(exponent)); var orbitalIntegralCanonical = orbitalIntegral.ToCanonicalForm(); //Logger.Message.WriteLine($"1e orbital { orbitalIntegral.Print()}, { orbitalIntegralCanonical.Print()}"); if (fileHIJTerms.ContainsKey(orbitalIntegralCanonical.OrbitalIndices)) { // Check consistency if (fileHIJTerms[orbitalIntegralCanonical.OrbitalIndices] != orbitalIntegral.Coefficient) { // Consistency check failed. throw new System.NotSupportedException( $"fileHPQTerm Consistency check fail. " + $"Orbital integral {orbitalIntegral} coefficient {orbitalIntegral.Coefficient}" + $"does not match recorded {orbitalIntegralCanonical} coefficient {fileHIJTerms[orbitalIntegral.OrbitalIndices]}."); } else { // Consistency check passed. } //Logger.Message.WriteLine($"1e orbital collision { orbitalIntegral.Print()}, { orbitalIntegralCanonical.Print()}"); } else { fileHIJTerms.Add(orbitalIntegralCanonical.OrbitalIndices, orbitalIntegralCanonical.Coefficient); } } } foreach (Match stringPQRS in regexPQRS.Matches(line)) { if (stringPQRS.Success) { var p = Int64.Parse(stringPQRS.Groups["p"].ToString()); var q = Int64.Parse(stringPQRS.Groups["q"].ToString()); var r = Int64.Parse(stringPQRS.Groups["r"].ToString()); var s = Int64.Parse(stringPQRS.Groups["s"].ToString()); var coeff = Double.Parse(stringPQRS.Groups["coeff"].ToString()); var exponentString = stringPQRS.Groups["exponent"].ToString(); var exponent = 0.0; if (exponentString != "") { exponent = Double.Parse(stringPQRS.Groups["exponent"].ToString()); } nOrbitals = new long[] { nOrbitals, p + 1, q + 1, r + 1, s + 1 }.Max(); var orbitalIntegral = new OrbitalIntegral(new Int64[] { p, q, r, s }, coeff * (10.0).Pow(exponent)); var orbitalIntegralCanonical = orbitalIntegral.ToCanonicalForm(); //Logger.Message.WriteLine($"2e orbital: { orbitalIntegral.Print()}, { orbitalIntegralCanonical.Print()}"); if (fileHIJKLTerms.ContainsKey(orbitalIntegralCanonical.OrbitalIndices)) { // Check consistency if (fileHIJKLTerms[orbitalIntegralCanonical.OrbitalIndices] != orbitalIntegral.Coefficient) { // Consistency check failed. throw new System.NotSupportedException( $"fileHPQRSTerm Consistency check fail. " + $"Orbital integral {orbitalIntegral.OrbitalIndices} coefficient {orbitalIntegral.Coefficient}" + $"does not match recorded {orbitalIntegralCanonical.OrbitalIndices} coefficient {fileHIJKLTerms[orbitalIntegral.OrbitalIndices]}."); } else { // Consistency check passed. } //Logger.Message.WriteLine($"2e orbital collision { orbitalIntegral.Print()}, { orbitalIntegralCanonical.Print()}"); } else { fileHIJKLTerms.Add(orbitalIntegralCanonical.OrbitalIndices, orbitalIntegralCanonical.Coefficient); } } } hamiltonian.NOrbitals = nOrbitals; foreach (var ijTerm in fileHIJTerms) { hamiltonian.AddFermionTerm(new OrbitalIntegral(ijTerm.Key, ijTerm.Value)); } foreach (var ijklTerm in fileHIJKLTerms) { hamiltonian.AddFermionTerm(new OrbitalIntegral(ijklTerm.Key, ijklTerm.Value)); } hamiltonian.SortAndAccumulate(); return(hamiltonian); }
internal static ElectronicStructureProblem DeserializeSingleProblem(string line) { var problem = new ElectronicStructureProblem() { Metadata = new Dictionary <string, object>() }; var regexMiscellaneous = new Regex(@"((info=(?<info>[^\s]*)))"); var regexnuc = new Regex(@"nuc=(?<nuc>-?\s*\d*.\d*)"); var regexPQ = new Regex(@"(^|\s+)(?<p>\d+),(?<q>\d+)\D*=\s*(?<coeff>-?\s*\d*.\d*)e?(?<exponent>-?\d*)"); var regexPQRS = new Regex(@"(^|\s+)(?<p>\d+)\D+(?<q>\d+)\D+(?<r>\d+)\D+(?<s>\d+)\D*=\s*(?<coeff>-?\s*\d*.\d*)e?(?<exponent>-?\d*)"); double coulombRepulsion = 0.0; var fileHIJTerms = new Dictionary <int[], double>(new Extensions.ArrayEqualityComparer <int>()); var fileHIJKLTerms = new Dictionary <int[], double>(new Extensions.ArrayEqualityComparer <int>()); var hamiltonian = new OrbitalIntegralHamiltonian(); var nOrbitals = 0L; Match stringMisc = regexMiscellaneous.Match(line); if (stringMisc.Success) { problem.Metadata["misc_info"] = stringMisc.Groups["info"].ToString(); } Match stringnuc = regexnuc.Match(line); if (stringnuc.Success) { coulombRepulsion = double.Parse(stringnuc.Groups["nuc"].ToString()).ToDoubleCoeff(); hamiltonian.Add(TermType.OrbitalIntegral.Identity, new OrbitalIntegral(), coulombRepulsion); } foreach (Match stringPQ in regexPQ.Matches(line)) { if (stringPQ.Success) { var p = int.Parse(stringPQ.Groups["p"].ToString()); var q = int.Parse(stringPQ.Groups["q"].ToString()); var coeff = double.Parse(stringPQ.Groups["coeff"].ToString()); var exponentString = stringPQ.Groups["exponent"].ToString(); var exponent = 0.0; if (exponentString != "") { exponent = double.Parse(stringPQ.Groups["exponent"].ToString()); } nOrbitals = new long[] { nOrbitals, p + 1, q + 1 }.Max(); var orbitalIntegral = new OrbitalIntegral(new int[] { p, q }, coeff * (10.0).Pow(exponent)); var orbitalIntegralCanonical = orbitalIntegral.ToCanonicalForm(); if (fileHIJTerms.ContainsKey(orbitalIntegralCanonical.OrbitalIndices)) { // Check consistency if (fileHIJTerms[orbitalIntegralCanonical.OrbitalIndices] != orbitalIntegral.Coefficient) { // Consistency check failed. throw new System.NotSupportedException( $"fileHPQTerm Consistency check fail. " + $"Orbital integral {orbitalIntegral} coefficient {orbitalIntegral.Coefficient}" + $"does not match recorded {orbitalIntegralCanonical} coefficient {fileHIJTerms[orbitalIntegral.OrbitalIndices]}."); } else { // Consistency check passed. } } else { fileHIJTerms.Add(orbitalIntegralCanonical.OrbitalIndices, orbitalIntegralCanonical.Coefficient); } } } foreach (Match stringPQRS in regexPQRS.Matches(line)) { if (stringPQRS.Success) { var p = int.Parse(stringPQRS.Groups["p"].ToString()); var q = int.Parse(stringPQRS.Groups["q"].ToString()); var r = int.Parse(stringPQRS.Groups["r"].ToString()); var s = int.Parse(stringPQRS.Groups["s"].ToString()); var coeff = double.Parse(stringPQRS.Groups["coeff"].ToString()); var exponentString = stringPQRS.Groups["exponent"].ToString(); var exponent = 0.0; if (exponentString != "") { exponent = double.Parse(stringPQRS.Groups["exponent"].ToString()); } nOrbitals = new long[] { nOrbitals, p + 1, q + 1, r + 1, s + 1 }.Max(); var orbitalIntegral = new OrbitalIntegral(new int[] { p, q, r, s }, coeff * (10.0).Pow(exponent)); var orbitalIntegralCanonical = orbitalIntegral.ToCanonicalForm(); if (fileHIJKLTerms.ContainsKey(orbitalIntegralCanonical.OrbitalIndices)) { // Check consistency if (fileHIJKLTerms[orbitalIntegralCanonical.OrbitalIndices] != orbitalIntegral.Coefficient) { // Consistency check failed. throw new System.NotSupportedException( $"fileHPQRSTerm Consistency check fail. " + $"Orbital integral {orbitalIntegral.OrbitalIndices} coefficient {orbitalIntegral.Coefficient}" + $"does not match recorded {orbitalIntegralCanonical.OrbitalIndices} coefficient {fileHIJKLTerms[orbitalIntegral.OrbitalIndices]}."); } else { // Consistency check passed. } } else { fileHIJKLTerms.Add(orbitalIntegralCanonical.OrbitalIndices, orbitalIntegralCanonical.Coefficient); } } } hamiltonian.Add(fileHIJTerms.Select(o => new OrbitalIntegral(o.Key, o.Value)).ToList()); hamiltonian.Add(fileHIJKLTerms.Select(o => new OrbitalIntegral(o.Key, o.Value)).ToList()); problem.OrbitalIntegralHamiltonian = hamiltonian; problem.NOrbitals = System.Convert.ToInt32(nOrbitals); problem.CoulombRepulsion = coulombRepulsion.WithUnits("hartree"); return(problem); }