Skip to content

Commit

Permalink
Merge branch 'main' into disable_workflows_in_forked_repository
Browse files Browse the repository at this point in the history
  • Loading branch information
sacpis authored Jul 15, 2024
2 parents 72e4c7f + 651afb4 commit c38c280
Show file tree
Hide file tree
Showing 27 changed files with 977 additions and 153 deletions.
6 changes: 2 additions & 4 deletions docs/sphinx/examples/cpp/algorithms/qaoa_maxcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,8 @@ int main() {
-M_PI / 8.0, M_PI / 8.0, n_params, std::mt19937::default_seed);

// Call the optimizer
auto [opt_val, opt_params] = cudaq::vqe(
ansatz{}, Hp, optimizer, n_params, [&](std::vector<double> params) {
return std::make_tuple(params, n_qubits, n_layers);
});
auto [opt_val, opt_params] =
cudaq::vqe(ansatz{}, Hp, optimizer, n_params, n_qubits, n_layers);

// Print the optimized value and the parameters
printf("Optimal value = %.16lf\n", opt_val);
Expand Down
8 changes: 2 additions & 6 deletions docs/sphinx/examples/cpp/algorithms/vqe_h2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,14 @@ int main() {

so4_fabric ansatz;

auto argMapper = [&](std::vector<double> x) {
return std::make_tuple(x, n_qubits, n_layers);
};

// Run VQE.
cudaq::optimizers::lbfgs optimizer;
optimizer.initial_parameters = init_params;
optimizer.max_eval = 20;
optimizer.max_line_search_trials = 10;
cudaq::gradients::central_difference gradient(ansatz, argMapper);
cudaq::gradients::central_difference gradient;
auto [opt_val, opt_params] =
cudaq::vqe(ansatz, gradient, H, optimizer, n_params, argMapper);
cudaq::vqe(ansatz, gradient, H, optimizer, n_params, n_qubits, n_layers);

printf("Optimal value = %.16lf\n", opt_val);
}
5 changes: 4 additions & 1 deletion include/cudaq/Optimizer/Builder/Factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ mlir::Type genArgumentBufferType(mlir::Type ty);
/// ```
/// where the values of the vector argument are pass-by-value and appended to
/// the end of the struct as a sequence of \i n double values.
cudaq::cc::StructType buildInvokeStructType(mlir::FunctionType funcTy);
///
/// The leading `startingArgIdx + 1` parameters are omitted from the struct.
cudaq::cc::StructType buildInvokeStructType(mlir::FunctionType funcTy,
std::size_t startingArgIdx = 0);

/// Return the LLVM-IR dialect type: `[length x i8]`.
inline mlir::Type getStringType(mlir::MLIRContext *ctx, std::size_t length) {
Expand Down
4 changes: 3 additions & 1 deletion include/cudaq/Optimizer/Transforms/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ std::unique_ptr<mlir::Pass> createObserveAnsatzPass(std::vector<bool> &);
std::unique_ptr<mlir::Pass> createQuakeAddMetadata();
std::unique_ptr<mlir::Pass> createQuakeAddDeallocs();
std::unique_ptr<mlir::Pass> createQuakeSynthesizer();
std::unique_ptr<mlir::Pass> createQuakeSynthesizer(std::string_view, void *);
std::unique_ptr<mlir::Pass>
createQuakeSynthesizer(std::string_view, const void *,
std::size_t startingArgIdx = 0);
std::unique_ptr<mlir::Pass> createRaiseToAffinePass();
std::unique_ptr<mlir::Pass> createUnwindLoweringPass();

Expand Down
2 changes: 2 additions & 0 deletions include/cudaq/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ def GenerateKernelExecution : Pass<"kernel-execution", "mlir::ModuleOp"> {
let options = [
Option<"outputFilename", "output-filename", "std::string",
/*default=*/"\"-\"", "Name of output file.">,
Option<"startingArgIdx", "starting-arg-idx", "std::size_t", /*default=*/"0",
"The starting argument index for the argsCreator.">,
];
}

Expand Down
9 changes: 6 additions & 3 deletions lib/Optimizer/Builder/Factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ Type factory::genArgumentBufferType(Type ty) {
return genBufferType</*isOutput=*/false>(ty);
}

cudaq::cc::StructType factory::buildInvokeStructType(FunctionType funcTy) {
cudaq::cc::StructType
factory::buildInvokeStructType(FunctionType funcTy,
std::size_t startingArgIdx) {
auto *ctx = funcTy.getContext();
SmallVector<Type> eleTys;
for (auto inTy : funcTy.getInputs())
eleTys.push_back(genBufferType</*isOutput=*/false>(inTy));
for (auto inTy : llvm::enumerate(funcTy.getInputs()))
if (inTy.index() >= startingArgIdx)
eleTys.push_back(genBufferType</*isOutput=*/false>(inTy.value()));
for (auto outTy : funcTy.getResults())
eleTys.push_back(genBufferType</*isOutput=*/true>(outTy));
return cudaq::cc::StructType::get(ctx, eleTys);
Expand Down
21 changes: 18 additions & 3 deletions lib/Optimizer/Transforms/GenKernelExecution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ class GenerateKernelExecution
builder.setInsertionPointToStart(entry);

// Get the original function args
auto kernelArgTypes = devKernelTy.getInputs();
auto kernelArgTypes = devKernelTy.getInputs().drop_front(startingArgIdx);

// Init the struct
Value stVal = builder.create<cudaq::cc::UndefOp>(loc, msgStructTy);
Expand Down Expand Up @@ -1531,8 +1531,23 @@ class GenerateKernelExecution
funcTy, funcOp);

// Generate the argsCreator function used by synthesis.
auto argsCreatorFunc = genKernelArgsCreatorFunction(
loc, builder, funcTy, structTy, classNameStr, hostFuncTy, hasThisPtr);
mlir::func::FuncOp argsCreatorFunc;
if (startingArgIdx == 0) {
argsCreatorFunc =
genKernelArgsCreatorFunction(loc, builder, funcTy, structTy,
classNameStr, hostFuncTy, hasThisPtr);
} else {
// We are operating in a very special case where we want the argsCreator
// function to ignore the first `startingArgIdx` arguments. In this
// situation, the argsCreator function will not be compatible with the
// other helper functions created in this pass, so it is assumed that
// the caller is OK with that.
auto structTy_argsCreator =
cudaq::opt::factory::buildInvokeStructType(funcTy, startingArgIdx);
argsCreatorFunc = genKernelArgsCreatorFunction(
loc, builder, funcTy, structTy_argsCreator, classNameStr,
hostFuncTy, hasThisPtr);
}

// Generate a new mangled function on the host side to call the
// callback function.
Expand Down
54 changes: 34 additions & 20 deletions lib/Optimizer/Transforms/QuakeSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ class state;
/// BlockArgument with it.
template <typename ConcreteType>
void synthesizeRuntimeArgument(
OpBuilder &builder, BlockArgument argument, void *args, std::size_t offset,
std::size_t typeSize,
OpBuilder &builder, BlockArgument argument, const void *args,
std::size_t offset, std::size_t typeSize,
std::function<Value(OpBuilder &, ConcreteType *)> &&opGenerator) {

// Create an instance of the concrete type
ConcreteType concrete;
// Copy the void* struct member into that concrete instance
std::memcpy(&concrete, ((char *)args) + offset, typeSize);
std::memcpy(&concrete, ((const char *)args) + offset, typeSize);

// Generate the MLIR Value (arith constant for example)
auto runtimeArg = opGenerator(builder, &concrete);
Expand Down Expand Up @@ -387,18 +387,26 @@ class QuakeSynthesizer
std::string kernelName;

// The raw pointer to the runtime arguments.
void *args;
const void *args;

// The starting argument index to synthesize. Typically 0 but may be >0 for
// partial synthesis. If >0, it is assumed that the first argument(s) are NOT
// in `args`.
std::size_t startingArgIdx = 0;

public:
QuakeSynthesizer() = default;
QuakeSynthesizer(std::string_view kernel, void *a)
QuakeSynthesizer(std::string_view kernel, const void *a)
: kernelName(kernel), args(a) {}
QuakeSynthesizer(std::string_view kernel, const void *a, std::size_t s)
: kernelName(kernel), args(a), startingArgIdx(s) {}

mlir::ModuleOp getModule() { return getOperation(); }

std::pair<std::size_t, std::vector<std::size_t>>
getTargetLayout(FunctionType funcTy) {
auto bufferTy = cudaq::opt::factory::buildInvokeStructType(funcTy);
auto bufferTy =
cudaq::opt::factory::buildInvokeStructType(funcTy, startingArgIdx);
StringRef dataLayoutSpec = "";
if (auto attr =
getModule()->getAttr(cudaq::opt::factory::targetDataLayoutAttrName))
Expand Down Expand Up @@ -449,10 +457,10 @@ class QuakeSynthesizer
// Keep track of the stdVec sizes.
std::vector<std::tuple<std::size_t, Type, std::uint64_t>> stdVecInfo;

for (auto iter : llvm::enumerate(arguments)) {
auto argNum = iter.index();
auto argument = iter.value();
std::size_t offset = structLayout.second[argNum];
for (std::size_t argNum = startingArgIdx, end = arguments.size();
argNum < end; argNum++) {
auto argument = arguments[argNum];
std::size_t offset = structLayout.second[argNum - startingArgIdx];

// Get the argument type
auto type = argument.getType();
Expand Down Expand Up @@ -560,9 +568,10 @@ class QuakeSynthesizer
signalPassFailure();
return;
}
char *ptrToSizeInBuffer = static_cast<char *>(args) + offset;
const char *ptrToSizeInBuffer =
static_cast<const char *>(args) + offset;
auto sizeFromBuffer =
*reinterpret_cast<std::uint64_t *>(ptrToSizeInBuffer);
*reinterpret_cast<const std::uint64_t *>(ptrToSizeInBuffer);
auto bytesInType = [&eleTy]() -> unsigned {
if (isa<cudaq::cc::CharspanType>(eleTy))
return 16 /*bytes: sizeof(ptr) + sizeof(i64)*/;
Expand All @@ -589,8 +598,10 @@ class QuakeSynthesizer
// TODO: for now we can ignore empty struct types.
continue;
}
char *ptrToSizeInBuffer = static_cast<char *>(args) + offset;
auto rawSize = *reinterpret_cast<std::uint64_t *>(ptrToSizeInBuffer);
const char *ptrToSizeInBuffer =
static_cast<const char *>(args) + offset;
auto rawSize =
*reinterpret_cast<const std::uint64_t *>(ptrToSizeInBuffer);
stdVecInfo.emplace_back(argNum, Type{}, rawSize);
continue;
}
Expand All @@ -604,7 +615,7 @@ class QuakeSynthesizer
// the block arg with the actual vector element data. First get the pointer
// to the start of the buffer's appendix.
auto structSize = structLayout.first;
char *bufferAppendix = static_cast<char *>(args) + structSize;
const char *bufferAppendix = static_cast<const char *>(args) + structSize;
for (auto [idx, eleTy, vecLength] : stdVecInfo) {
if (!eleTy) {
// FIXME: Skip struct values.
Expand All @@ -614,7 +625,7 @@ class QuakeSynthesizer
continue;
}
auto doVector = [&]<typename T>(T) {
auto *ptr = reinterpret_cast<T *>(bufferAppendix);
auto *ptr = reinterpret_cast<const T *>(bufferAppendix);
std::vector<T> v(ptr, ptr + vecLength);
if (failed(synthesizeVectorArgument(builder, module, counter,
arguments[idx], v)))
Expand Down Expand Up @@ -667,7 +678,8 @@ class QuakeSynthesizer
// of sizes that are encoded starting at bufferAppendix.
// At the end of the block of sizes, the C-strings will be encoded.
auto numberSpans = vecLength;
auto *spanSizes = reinterpret_cast<std::uint64_t *>(bufferAppendix);
auto *spanSizes =
reinterpret_cast<const std::uint64_t *>(bufferAppendix);
bufferAppendix += vecLength * sizeof(std::uint64_t);
// These strings are reified in the following way:
// - Create an array numberSpans in length and where each element
Expand Down Expand Up @@ -726,7 +738,8 @@ class QuakeSynthesizer
// Remove the old arguments.
auto numArgs = funcOp.getNumArguments();
BitVector argsToErase(numArgs);
for (std::size_t argIndex = 0; argIndex < numArgs; ++argIndex) {
for (std::size_t argIndex = startingArgIdx; argIndex < numArgs;
++argIndex) {
argsToErase.set(argIndex);
if (!funcOp.getBody().front().getArgument(argIndex).getUses().empty()) {
funcOp.emitError("argument(s) still in use after synthesis.");
Expand All @@ -745,6 +758,7 @@ std::unique_ptr<mlir::Pass> cudaq::opt::createQuakeSynthesizer() {
}

std::unique_ptr<mlir::Pass>
cudaq::opt::createQuakeSynthesizer(std::string_view kernelName, void *a) {
return std::make_unique<QuakeSynthesizer>(kernelName, a);
cudaq::opt::createQuakeSynthesizer(std::string_view kernelName, const void *a,
std::size_t startingArgIdx) {
return std::make_unique<QuakeSynthesizer>(kernelName, a, startingArgIdx);
}
Loading

0 comments on commit c38c280

Please sign in to comment.