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

Expose Jordan Wigner to Python. Add HTTP server for cudaq-pyscf #5

Merged
merged 6 commits into from
Jul 25, 2024
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
3 changes: 2 additions & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ jobs:
--build-arg="repo=${{github.event.pull_request.head.repo.full_name}}" -t cudaqlib-dev:local -f docker/ci/Dockerfile .

- name: Run tests
run: docker run --rm cudaqlib-dev:local ctest --output-on-failure --test-dir cudaqlib/build
run: docker run --rm cudaqlib-dev:local ctest --output-on-failure --test-dir cudaqlib/build \
&& docker run --rm cudaqlib-dev:local python3 -m pytest cudaqlib/python/tests -v
5 changes: 2 additions & 3 deletions cudaqlib/gse.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
#pragma once

#include "gse/adapt/adapt.h"
#include "gse/vqe/vqe.h"
#include "gse/utils/operator_pool.h"
#include "gse/utils/pools/uccsd_pool.h"
#include "gse/utils/pools/spin_complement_gsd.h"

#include "gse/utils/pools/uccsd_pool.h"
#include "gse/vqe/vqe.h"
7 changes: 4 additions & 3 deletions cudaqlib/gse/adapt/adapt.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ struct AdaptKernel {

template <typename InitialState>
auto adapt_vqe(const InitialState &initialState, const spin_op &H,
const std::vector<spin_op> &poolList, optim::optimizer &optimizer,
observe_gradient *gradient,
const std::vector<spin_op> &poolList,
optim::optimizer &optimizer, observe_gradient *gradient,
const adapt_options options = adapt_options()) {

AdaptKernel kernel;
Expand Down Expand Up @@ -112,7 +112,8 @@ auto adapt_vqe(const InitialState &initialState, const spin_op &H,

template <typename InitialState>
auto adapt_vqe(const InitialState &initialState, const spin_op &H,
const std::vector<spin_op> &operatorPool, optim::optimizer &optimizer,
const std::vector<spin_op> &operatorPool,
optim::optimizer &optimizer,
const adapt_options options = adapt_options()) {
return adapt_vqe(initialState, H, operatorPool, optimizer, nullptr, options);
}
Expand Down
1 change: 1 addition & 0 deletions cudaqlib/gse/utils/operator_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ inline std::size_t getIntLike(const std::any &any) {
class operator_pool : public extension_point<operator_pool> {
public:
operator_pool() = default;
virtual ~operator_pool() {}
virtual std::vector<spin_op>
generate(const std::unordered_map<std::string, std::any> &config) const = 0;
};
Expand Down
1 change: 0 additions & 1 deletion cudaqlib/gse/utils/pools/spin_complement_gsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ std::vector<spin_op> spin_complement_gsd::generate(

auto numOrbitals = std::any_cast<std::size_t>(iter->second);


std::vector<spin_op> pool;
auto numQubits = 2 * numOrbitals;
std::vector<int> alphaOrbs, betaOrbs;
Expand Down
3 changes: 2 additions & 1 deletion cudaqlib/operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
#pragma once

#include "operators/chemistry/MoleculePackageDriver.h"
#include "operators/fermion/fermion_to_spin.h"
#include "operators/fermion/fermion_to_spin.h"
#include "operators/fermion/transformations/jordan_wigner.h"
9 changes: 5 additions & 4 deletions cudaqlib/operators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ add_library(${LIBRARY_NAME} SHARED
fermion/transformations/jordan_wigner.cpp
# chemistry package drivers
chemistry/drivers/pyscf/ExternalPySCFDriver.cpp
chemistry/drivers/pyscf/RESTPySCFDriver.cpp
)


target_link_libraries(${LIBRARY_NAME} PUBLIC cudaq::cudaq)
target_include_directories(${LIBRARY_NAME}
PRIVATE
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<BUILD_INTERFACE:${CUDAQ_INCLUDE_DIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/json>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/json/include>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/cppitertools/cppitertools>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/xtl/include>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/tpls/xtensor/include>
PUBLIC
$<INSTALL_INTERFACE:${CUDAQ_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>)

target_link_libraries(${LIBRARY_NAME} PUBLIC cudaq::cudaq)

install(
TARGETS ${LIBRARY_NAME}
EXPORT ${LIBRARY_NAME}Targets
Expand All @@ -44,4 +45,4 @@ install(
DESTINATION lib/cmake/operators)

install(FILES "${CMAKE_SOURCE_DIR}/cmake/${LIBRARY_NAME}Config.cmake"
DESTINATION lib/cmake/operators)
DESTINATION lib/cmake/operators)
3 changes: 2 additions & 1 deletion cudaqlib/operators/chemistry/MoleculePackageDriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ class MoleculePackageDriver : public extension_point<MoleculePackageDriver> {
int spin, int charge,
molecule_options options = molecule_options()) = 0;

virtual bool is_available() const { return true; }
/// Virtual destructor needed when deleting an instance of a derived class
/// via a pointer to the base class.
virtual ~MoleculePackageDriver(){};
};

CUDAQ_DEFINE_EXTENSION_IMPL(MoleculePackageDriver)

#define CUDAQ_REGISTER_MOLECULEPACKAGEDRIVER(TYPE) \
#define CUDAQ_REGISTER_MOLECULEPACKAGEDRIVER(TYPE) \
static inline const std::string class_identifier = #TYPE; \
static std::unique_ptr<MoleculePackageDriver> create() { \
return std::make_unique<TYPE>(); \
Expand Down
56 changes: 32 additions & 24 deletions cudaqlib/operators/chemistry/drivers/pyscf/ExternalPySCFDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#include "json.hpp"
#include "nlohmann/json.hpp"

#include "cudaqlib/operators/chemistry/MoleculePackageDriver.h"
#include "cudaqlib/operators/fermion/fermion_to_spin.h"
Expand Down Expand Up @@ -45,10 +45,10 @@ class external_pyscf
std::string oneBodyFile = outFileName + "_one_body.dat";
std::string twoBodyFile = outFileName + "_two_body.dat";
std::string metadataFile = outFileName + "_metadata.json";
std::filesystem::path libPath{cudaqlib::__internal__::getCUDAQLibraryPath()};
std::filesystem::path libPath{
cudaqlib::__internal__::getCUDAQLibraryPath()};
auto cudaqLibPath = libPath.parent_path();
auto cudaqPySCFTool =
cudaqLibPath.parent_path() / "bin" / "cudaq-pyscf.py";
auto cudaqPySCFTool = cudaqLibPath.parent_path() / "bin" / "cudaq-pyscf.py";

// Convert the geometry to an XYZ string
for (auto &atom : geometry)
Expand All @@ -58,11 +58,12 @@ class external_pyscf
xyzFileStr = "\"" + xyzFileStr + "\"";

std::string argString = fmt::format(
"{} --type {} --xyz {} --charge {} --spin {} --basis {} --out-file-name {} "
"{} --type {} --xyz {} --charge {} --spin {} --basis {} "
"--out-file-name {} "
"{} --memory {} {} --cycles {} --initguess {} {} {} {} {} {} {} {} {} "
"{} {} {}",
cudaqPySCFTool.string(), options.type, xyzFileStr, charge, spin, basis, outFileName,
options.verbose ? "--verbose" : "", options.memory,
cudaqPySCFTool.string(), options.type, xyzFileStr, charge, spin, basis,
outFileName, options.verbose ? "--verbose" : "", options.memory,
options.symmetry ? "--symmetry" : "", options.cycles, options.initguess,
options.UR ? "--UR" : "",
options.nele_cas.has_value()
Expand All @@ -87,35 +88,42 @@ class external_pyscf
// Import all the data we need from the execution.
std::ifstream f(metadataFile);
auto metadata = nlohmann::json::parse(f);
metadata.dump();
auto oneVec = readInData(oneBodyFile);
auto twoVec = readInData(twoBodyFile);
std::remove(metadataFile.c_str());
std::remove(oneBodyFile.c_str());
std::remove(twoBodyFile.c_str());

printf("TEST\n%s\n", metadata.dump(4).c_str());
// Get the energy, num orbitals, and num qubits
auto energy = metadata["nuclear_energy"].get<double>();
std::unordered_map<std::string, double> energies;
for (auto &[energyName, E] : metadata["energies"].items())
energies.insert({energyName, E});

double energy = 0.0;
if (energies.contains("nuclear_energy"))
energy = energies["nuclear_energy"];
else if (energies.contains("core_energy"))
energy = energies["core_energy"];

auto numOrb = metadata["num_orbitals"].get<std::size_t>();
auto numQubits = 2 * numOrb;
auto num_electrons = metadata["num_electrons"].get<std::size_t>();

// Create the fermion operator
// Get the operators
fermion_op fermionOp(numQubits, energy);
fermionOp.hpq.set_data(oneVec);
fermionOp.hpqrs.set_data(twoVec);
auto hpqElements = metadata["hpq"]["data"];
auto hpqrsElements = metadata["hpqrs"]["data"];
std::vector<std::complex<double>> hpqValues, hpqrsValues;
for (auto &element : hpqElements)
hpqValues.push_back({element[0].get<double>(), element[1].get<double>()});
for (auto &element : hpqrsElements)
hpqrsValues.push_back(
{element[0].get<double>(), element[1].get<double>()});
fermionOp.hpq.set_data(hpqValues);
fermionOp.hpqrs.set_data(hpqrsValues);

// Transform to a spin operator
auto transform = fermion_to_spin::get(options.fermion_to_string);
auto spinHamiltonian = transform->generate(fermionOp);

// Return the molecular hamiltonian
return operators::molecular_hamiltonian{
spinHamiltonian,
std::move(fermionOp),
metadata["num_electrons"].get<std::size_t>(),
numOrb,
energy,
metadata["hf_energy"].get<double>()};
spinHamiltonian, std::move(fermionOp), num_electrons, numOrb, energies};
}

CUDAQ_REGISTER_MOLECULEPACKAGEDRIVER(external_pyscf)
Expand Down
123 changes: 123 additions & 0 deletions cudaqlib/operators/chemistry/drivers/pyscf/RESTPySCFDriver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*******************************************************************************
* Copyright (c) 2022 - 2023 NVIDIA Corporation & Affiliates. *
* All rights reserved. *
* *
* This source code and the accompanying materials are made available under *
* the terms of the Apache License 2.0 which accompanies this distribution. *
******************************************************************************/

#include "nlohmann/json.hpp"

#include "cudaqlib/operators/chemistry/MoleculePackageDriver.h"
#include "cudaqlib/operators/fermion/fermion_to_spin.h"
#include "cudaqlib/utils/library_utils.h"

#include "common/RestClient.h"

#include <filesystem>
#include <fmt/core.h>
#include <fstream>

namespace cudaq::operators {

class RESTPySCFDriver
: public details::MoleculePackageDriver_impl<RESTPySCFDriver> {

public:
bool is_available() const override {
RestClient client;
std::map<std::string, std::string> headers;
try {
auto res = client.get("localhost:8000/", "status", headers);
if (res.contains("status") &&
res["status"].get<std::string>() == "available")
return true;
} catch (std::exception &e) {
return false;
}
return true;
}

/// @brief Create the molecular hamiltonian
operators::molecular_hamiltonian
createMolecule(const molecular_geometry &geometry, const std::string &basis,
int spin, int charge, molecule_options options) override {
std::string xyzFileStr = "";
// Convert the geometry to an XYZ string
for (auto &atom : geometry)
xyzFileStr +=
fmt::format("{} {:f} {:f} {:f}; ", atom.name, atom.coordinates[0],
atom.coordinates[1], atom.coordinates[2]);

RestClient client;
nlohmann::json payload = {{"xyz", xyzFileStr},
{"basis", basis},
{"spin", spin},
{"charge", charge},
{"type", "gas_phase"},
{"symmetry", false},
{"cycles", options.cycles},
{"initguess", options.initguess},
{"UR", options.UR},
{"MP2", options.MP2},
{"natorb", options.natorb},
{"casci", options.casci},
{"ccsd", options.ccsd},
{"casscf", options.casscf},
{"integrals_natorb", options.integrals_natorb},
{"integrals_casscf", options.integrals_casscf},
{"verbose", options.verbose}};
if (options.nele_cas.has_value())
payload["nele_cas"] = options.nele_cas.value();
if (options.norb_cas.has_value())
payload["norb_cas"] = options.norb_cas.value();
if (options.potfile.has_value())
payload["potfile"] = options.potfile.value();

std::map<std::string, std::string> headers{
{"Content-Type", "application/json"}};
auto metadata = client.post("localhost:8000/", "create_molecule", payload,
headers, true);

// Get the energy, num orbitals, and num qubits
std::unordered_map<std::string, double> energies;
for (auto &[energyName, E] : metadata["energies"].items())
energies.insert({energyName, E});

double energy = 0.0;
if (energies.contains("nuclear_energy"))
energy = energies["nuclear_energy"];
else if (energies.contains("core_energy"))
energy = energies["core_energy"];

auto numOrb = metadata["num_orbitals"].get<std::size_t>();
auto numQubits = 2 * numOrb;
auto num_electrons = metadata["num_electrons"].get<std::size_t>();

// Get the operators
fermion_op fermionOp(numQubits, energy);
std::unordered_map<std::string, fermion_op> operators;
auto hpqElements = metadata["hpq"]["data"];
auto hpqrsElements = metadata["hpqrs"]["data"];
std::vector<std::complex<double>> hpqValues, hpqrsValues;
for (auto &element : hpqElements)
hpqValues.push_back({element[0].get<double>(), element[1].get<double>()});
for (auto &element : hpqrsElements)
hpqrsValues.push_back(
{element[0].get<double>(), element[1].get<double>()});
fermionOp.hpq.set_data(hpqValues);
fermionOp.hpqrs.set_data(hpqrsValues);

// Transform to a spin operator
auto transform = fermion_to_spin::get(options.fermion_to_string);
auto spinHamiltonian = transform->generate(fermionOp);

// Return the molecular hamiltonian
return operators::molecular_hamiltonian{
spinHamiltonian, std::move(fermionOp), num_electrons, numOrb, energies};
}

CUDAQ_REGISTER_MOLECULEPACKAGEDRIVER(RESTPySCFDriver)
};

} // namespace cudaq::operators
Loading