Skip to content

Commit

Permalink
Expose Jordan Wigner to Python. Add HTTP server for cudaq-pyscf (#5)
Browse files Browse the repository at this point in the history
* Add JW to python, add http server for pyscf

Signed-off-by: Alex McCaskey <[email protected]>

* cleanup

Signed-off-by: Alex McCaskey <[email protected]>

* clang format

Signed-off-by: Alex McCaskey <[email protected]>

* fix error

Signed-off-by: Alex McCaskey <[email protected]>

* cleanup

Signed-off-by: Alex McCaskey <[email protected]>

* add one particle op

Signed-off-by: Alex McCaskey <[email protected]>

---------

Signed-off-by: Alex McCaskey <[email protected]>
  • Loading branch information
amccaskey authored Jul 25, 2024
1 parent 438e4db commit 475079b
Show file tree
Hide file tree
Showing 32 changed files with 1,603 additions and 1,641 deletions.
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

0 comments on commit 475079b

Please sign in to comment.