Skip to content
Open
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
11 changes: 1 addition & 10 deletions libs/core/include/cuda-qx/core/heterogeneous_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ class heterogeneous_map {
/// @return true if castable, false otherwise
template <typename T>
bool isCastable(const std::any &t) const {
try {
std::any_cast<T>(t);
} catch (...) {
return false;
}
return true;
return std::any_cast<T>(&t) != nullptr;
}

public:
Expand Down Expand Up @@ -122,8 +117,6 @@ class heterogeneous_map {
throw std::runtime_error(
"heterogeneous_map::get() error - Invalid type or key (" + keyStr +
").");

return T();
}

/// @brief Get a value from the map, search for the value
Expand All @@ -149,8 +142,6 @@ class heterogeneous_map {

throw std::runtime_error(
"heterogeneous_map::get(keys) error - Invalid keys (" + keyStr + ").");

return T();
}

template <typename T>
Expand Down
3 changes: 1 addition & 2 deletions libs/qec/lib/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,7 @@ void decoder::set_D_sparse(const std::vector<int64_t> &D_sparse_vec_in) {
bool decoder::enqueue_syndrome(const uint8_t *syndrome,
std::size_t syndrome_length) {
if (pimpl->msyn_buffer_index + syndrome_length > pimpl->msyn_buffer.size()) {
// CUDAQ_WARN("Syndrome buffer overflow. Syndrome will be ignored.");
printf("Syndrome buffer overflow. Syndrome will be ignored.\n");
cudaq::info("Syndrome buffer overflow. Syndrome will be ignored.");
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions libs/qec/lib/pcm_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ cudaqx::tensor<uint8_t> generate_random_pcm(std::size_t n_rounds,
std::size_t row_max = all_errors_in_this_round
? n_syndromes_per_round
: 2 * n_syndromes_per_round;
if (static_cast<std::size_t>(weight) > row_max) {
throw std::invalid_argument(
"generate_random_pcm: weight exceeds available rows per column");
}
std::uniform_int_distribution<> row_dis(0, row_max - 1);
for (std::size_t i = 0; i < weight; ++i) {
auto row_ix = row_dis(rng);
Expand Down
30 changes: 14 additions & 16 deletions libs/solvers/include/cudaq/solvers/vqe.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include "optimizer.h"
#include <utility>

using namespace cudaqx;

namespace cudaq::solvers {

/// @brief A vqe_result encapsulates all the data produced
Expand Down Expand Up @@ -47,7 +45,7 @@ static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
optim::optimizer &optimizer,
observe_gradient &gradient,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {
if (!optimizer.requiresGradients())
throw std::runtime_error("[vqe] provided optimizer does not require "
"gradients, yet gradient instance provided.");
Expand Down Expand Up @@ -83,13 +81,13 @@ static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
const std::string &optName,
const std::string &gradName,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (!cudaq::optim::optimizer::is_registered(optName))
throw std::runtime_error("provided optimizer is not valid.");

if (!cudaq::observe_gradient::is_registered(gradName))
throw std::runtime_error("provided optimizer is not valid.");
throw std::runtime_error("provided gradient strategy is not valid.");

auto optimizer = cudaq::optim::optimizer::get(optName);
auto gradient = cudaq::observe_gradient::get(gradName, kernel, hamiltonian);
Expand Down Expand Up @@ -128,7 +126,7 @@ template <typename QuantumKernel>
static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
const std::string &optName,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (!cudaq::optim::optimizer::is_registered(optName))
throw std::runtime_error("provided optimizer is not valid.");
Expand Down Expand Up @@ -166,7 +164,7 @@ static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
const std::string &optName,
observe_gradient &gradient,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (!cudaq::optim::optimizer::is_registered(optName))
throw std::runtime_error("provided optimizer is not valid.");
Expand Down Expand Up @@ -207,10 +205,10 @@ static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
optim::optimizer &optimizer,
const std::string &gradName,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (!cudaq::observe_gradient::is_registered(gradName))
throw std::runtime_error("provided optimizer is not valid.");
throw std::runtime_error("provided gradient strategy is not valid.");

auto gradient = cudaq::observe_gradient::get(gradName, kernel, hamiltonian);

Expand Down Expand Up @@ -247,11 +245,11 @@ template <typename QuantumKernel>
static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
optim::optimizer &optimizer,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (optimizer.requiresGradients())
throw std::runtime_error("[vqe] provided optimizer does not require "
"gradients, yet gradient instance provided.");
throw std::runtime_error("[vqe] provided optimizer requires "
"gradients, yet no gradient instance provided.");

options.insert("initial_parameters", initial_parameters);

Expand All @@ -278,7 +276,7 @@ template <typename QuantumKernel>
requires std::invocable<QuantumKernel, std::vector<double>>
static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
const std::vector<double> &initial_parameters,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

auto optimizer = optim::optimizer::get("cobyla");
options.insert("initial_parameters", initial_parameters);
Expand Down Expand Up @@ -307,7 +305,7 @@ static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
optim::optimizer &optimizer,
const std::vector<double> &initial_parameters,
ArgTranslator &&translator,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (optimizer.requiresGradients())
throw std::runtime_error("[vqe] provided optimizer requires "
Expand Down Expand Up @@ -341,7 +339,7 @@ template <typename QuantumKernel, typename ArgTranslator>
static inline vqe_result vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
const std::vector<double> &initial_parameters,
ArgTranslator &&translator,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

auto optimizer = optim::optimizer::get("cobyla");
options.insert("initial_parameters", initial_parameters);
Expand Down Expand Up @@ -373,7 +371,7 @@ static inline vqe_result
vqe(QuantumKernel &&kernel, const spin_op &hamiltonian,
optim::optimizer &optimizer, observe_gradient &gradient,
const std::vector<double> &initial_parameters, ArgTranslator &&translator,
heterogeneous_map options = heterogeneous_map()) {
cudaqx::heterogeneous_map options = cudaqx::heterogeneous_map()) {

if (!optimizer.requiresGradients())
throw std::runtime_error("[vqe] provided optimizer does not require "
Expand Down
60 changes: 39 additions & 21 deletions libs/solvers/lib/operators/molecule/drivers/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,59 +14,77 @@

namespace cudaqx {

/// @brief RAII guard to unlink a temporary file on scope exit.
struct TempFileGuard {
const char *path;
TempFileGuard(const char *p) : path(p) {}
~TempFileGuard() {
if (path)
unlink(path);
}
// Non-copyable
TempFileGuard(const TempFileGuard &) = delete;
TempFileGuard &operator=(const TempFileGuard &) = delete;
};

std::pair<pid_t, std::string> launchProcess(const char *command) {
// Create temporary files for storing stdout and stderr
// Create temporary files for storing stdout and stderr.
// mkstemp atomically creates and opens the file, preventing symlink attacks.
char tempStdout[] = "/tmp/stdout_XXXXXX";
char tempStderr[] = "/tmp/stderr_XXXXXX";

int fdOut = mkstemp(tempStdout);
int fdErr = mkstemp(tempStderr);
if (fdOut == -1) {
throw std::runtime_error("Failed to create temporary stdout file");
}

if (fdOut == -1 || fdErr == -1) {
throw std::runtime_error("Failed to create temporary files");
int fdErr = mkstemp(tempStderr);
if (fdErr == -1) {
close(fdOut);
unlink(tempStdout);
throw std::runtime_error("Failed to create temporary stderr file");
}

// Construct command to redirect both stdout and stderr to temporary files
// Close the FDs immediately — we only needed mkstemp for atomic file
// creation. The shell redirect will reopen by filename, but since we created
// the files atomically, no symlink attack is possible on the initial create.
close(fdOut);
close(fdErr);

// Ensure temporary files are cleaned up on all exit paths.
TempFileGuard guardOut(tempStdout);
TempFileGuard guardErr(tempStderr);

// Construct command to redirect both stdout and stderr to temporary files.
std::string argString = std::string(command) + " 1>" + tempStdout + " 2>" +
tempStderr + " & echo $!";

// Launch the process
FILE *pipe = popen(argString.c_str(), "r");
if (!pipe) {
close(fdOut);
close(fdErr);
unlink(tempStdout);
unlink(tempStderr);
throw std::runtime_error("Error launching process: " +
std::string(command));
}

// Read PID
char buffer[128];
std::string pidStr = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != nullptr)
pidStr += buffer;
}
std::string pidStr;
while (fgets(buffer, sizeof(buffer), pipe) != nullptr)
pidStr += buffer;
pclose(pipe);

std::this_thread::sleep_for(std::chrono::milliseconds(100));

// Read any error output
std::string errorOutput;
FILE *errorFile = fopen(tempStderr, "r");
if (errorFile) {
while (fgets(buffer, 128, errorFile) != nullptr) {
while (fgets(buffer, sizeof(buffer), errorFile) != nullptr) {
errorOutput += buffer;
}
fclose(errorFile);
}

// Clean up temporary files
close(fdOut);
close(fdErr);
unlink(tempStdout);
unlink(tempStderr);

// Convert PID string to integer
pid_t pid = 0;
try {
Expand Down