// This file is part of GQCG-GQCP.
//
// Copyright (C) 2017-2020  the GQCG developers
//
// GQCG-GQCP is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GQCG-GQCP is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GQCG-GQCP.  If not, see <http://www.gnu.org/licenses/>.

#include "QCMethod/HF/RHF/RHFSCFSolver.hpp"
#include "Utilities/complex.hpp"
#include "gqcpy/include/interfaces.hpp"

#include <pybind11/pybind11.h>


namespace gqcpy {


// Provide some shortcuts for frequent namespaces.
namespace py = pybind11;
using namespace GQCP;


/**
 *  Add Python bindings for some APIs related to RHF SCF solvers.
 * 
 *  @tparam Class               The type of the Pybind11 `class_` (generated by the compiler).
 *  
 *  @param py_class             The Pybind11 `class_` that should obtain APIs related to RHF SCF solvers.
 */
template <typename Class>
void bindRHFSCFSolverInterface(Class& py_class) {

    // The C++ type corresponding to the Python class.
    using Type = typename Class::type;
    using Scalar = typename Type::Scalar;


    py_class
        .def_static(
            "DensityDamped",
            [](const double alpha, const double threshold, const size_t maximum_number_of_iterations) {
                return RHFSCFSolver<double>::DensityDamped(alpha, threshold, maximum_number_of_iterations);
            },
            py::arg("alpha"),
            py::arg("threshold") = 1.0e-08,
            py::arg("maximum_number_of_iterations") = 128,
            "Return a density-damped RHF SCF solver that uses the norm of the difference of two consecutive density matrices as a convergence criterion.");
}


/*
 *  Add Python bindings for RHF SCF solvers.
 */
void bindRHFSCFSolvers(py::module& module) {

    // Provide bindings for real-valued RHF SCF solvers.
    py::class_<RHFSCFSolver<double>> py_RHFSCFSolver_d {module, "RHFSCFSolver_d", "A factory that can create real-valued RHF SCF solvers."};

    bindHartreeFockSCFSolverInterface(py_RHFSCFSolver_d);
    bindRHFSCFSolverInterface(py_RHFSCFSolver_d);


    // Provide bindings for complex-valued RHF SCF solvers.
    py::class_<RHFSCFSolver<complex>> py_RHFSCFSolver_cd {module, "RHFSCFSolver_cd", "A factory that can create complex-valued RHF SCF solvers."};

    bindHartreeFockSCFSolverInterface(py_RHFSCFSolver_cd);
    bindRHFSCFSolverInterface(py_RHFSCFSolver_cd);
}


}  // namespace gqcpy
