/// <summary>
 /// This approximates the Hamiltonian ground state by a greedy algorithm
 /// that minimizes only the PP term energies. If there are no PP terms,
 /// states will be occupied in lexicographic order.
 /// </summary>
 /// <returns>
 /// Greedy trial state for minimizing Hamiltonian diagonal one-electron energy.
 /// </returns>
 internal static SingleCFWavefunction <int> GreedyStatePreparationSCF(this FermionHamiltonian hamiltonian, int nElectrons)
 {
     if (hamiltonian.Terms.ContainsKey(TermType.Fermion.PP))
     {
         var hPPTermSortedByCoeff = hamiltonian.Terms[TermType.Fermion.PP];
         var spinOrbitalIndices   = hPPTermSortedByCoeff.OrderBy(o => o.Value).Select(o => o.Key.Sequence.First().Index).Take((int)nElectrons).ToArray();
         return(new SingleCFWavefunction <int>(spinOrbitalIndices));
     }
     else
     {
         return(new SingleCFWavefunction <int>(Enumerable.Range(0, nElectrons).ToArray()));
     }
 }
        /// <summary>
        /// This approximates the Hamiltonian ground state by a greedy algorithm
        /// that minimizes only the PP term energies. If there are no PP terms,
        /// states will be occupied in lexicographic order.
        /// </summary>
        /// <returns>
        /// Greedy trial state for minimizing Hamiltonian diagonal one-electron energy.
        /// </returns>
        public static FermionWavefunction <int> CreateHartreeFockState(this FermionHamiltonian hamiltonian, int nElectrons)
        {
            SingleCFWavefunction <int> greedyState = hamiltonian.GreedyStatePreparationSCF(nElectrons);

            var wavefunction = new FermionWavefunction <int>
            {
                Energy  = 0.0,
                Method  = StateType.SparseMultiConfigurational,
                MCFData = new SparseMultiCFWavefunction <int>()
            };

            wavefunction.MCFData.Set(greedyState, new System.Numerics.Complex(1.0, 0.0));

            return(wavefunction);
        }
        /// <summary>
        /// Method for constructing a Pauli Hamiltonian from a fermion Hamiltonina.
        /// </summary>
        /// <param name="sourceHamiltonian">Input orbital integral Hamiltonian.</param>
        /// <param name="encoding">Identifies how the terms should be encoded on the qubits.</param>
        /// <returns>Fermion Hamiltonian constructed from orbital integrals.</returns>
        public static PauliHamiltonian ToPauliHamiltonian(
            this FermionHamiltonian sourceHamiltonian,
            QubitEncoding encoding = QubitEncoding.JordanWigner)
        {
            var nFermions   = sourceHamiltonian.SystemIndices.Max() + 1;
            var hamiltonian = new PauliHamiltonian();
            Func <FermionTerm, TermType.Fermion, double, IEnumerable <(PauliTerm, PauliTermValue)> > conversion =
                (fermionTerm, termType, coeff)
                => (fermionTerm.ToJordanWignerPauliTerms(termType, coeff));

            foreach (var termType in sourceHamiltonian.Terms)
            {
                foreach (var term in termType.Value)
                {
                    hamiltonian.AddRange(conversion(term.Key, termType.Key, term.Value.Value));
                }
            }
            // Create a copy of fermion indices hash set.
            hamiltonian.SystemIndices = new HashSet <int>(sourceHamiltonian.SystemIndices.ToList());
            return(hamiltonian);
        }