/// <summary> /// Creates all fermion terms generated by all symmetries of an orbital integral. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="orbitalIntegral">Input orbital integral.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> /// <returns>List of fermion terms generated by all symmetries of an orbital integral.</returns> public static IEnumerable <(HermitianFermionTerm, double)> ToHermitianFermionTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention = IndexConvention.UpDown) { var termType = orbitalIntegral.TermType; if (termType == TermType.OrbitalIntegral.OneBody) { return(orbitalIntegral.ToOneBodySpinOrbitalTerms(nOrbitals, indexConvention)); } else if (termType == TermType.OrbitalIntegral.TwoBody) { return(orbitalIntegral.ToTwoBodySpinOrbitalTerms(nOrbitals, indexConvention)); } else if (termType == TermType.OrbitalIntegral.Identity) { return(new List <(HermitianFermionTerm, double)>() { (new HermitianFermionTerm(), orbitalIntegral.Coefficient) }); } else { throw new System.NotImplementedException(); } }
/// <summary> /// Creates all fermion terms generated by all symmetries of a one-body orbital integral. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="orbitalIntegral">Input orbital integral.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> private static IEnumerable <(HermitianFermionTerm, double)> ToOneBodySpinOrbitalTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention) { // One-electron orbital integral symmetries // ij = ji var pqSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals(); var coefficient = orbitalIntegral.Coefficient; foreach (var pq in pqSpinOrbitals) { var pInt = pq[0].ToInt(indexConvention, nOrbitals); var qInt = pq[1].ToInt(indexConvention, nOrbitals); if (pInt == qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), orbitalIntegral.Coefficient); } else if (pInt < qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), 2.0 * orbitalIntegral.Coefficient); } } }
/// <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="orbitalIntegral">Sequence of four-body orbital integrals.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> private static IEnumerable <(HermitianFermionTerm, double)> ToTwoBodySpinOrbitalTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention) { List <(HermitianFermionTerm, double)> fermionTerms = new List <(HermitianFermionTerm, double)>(); // 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(indexConvention, nOrbitals); var qInt = q.ToInt(indexConvention, nOrbitals); var rInt = r.ToInt(indexConvention, nOrbitals); var sInt = s.ToInt(indexConvention, nOrbitals); // 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 yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 1.0 * coefficient); } else if (pInt == rInt && qInt == sInt && pInt < qInt) { // iU jU iU jU | iD jD iD jD // PQPQ yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -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) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, sInt, rInt }.ToLadderSequence()), 2.0 * coefficient); } } else { if (pInt < qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, rInt, sInt }.ToLadderSequence()), -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) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, rInt, sInt }.ToLadderSequence()), -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) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } } } }