From f557ab9ca516a7ac1d131228a7c00a8fd9f6d106 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 11:07:20 -0500 Subject: [PATCH 01/61] add json library attribution --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 78aac581df..8c5f497054 100644 --- a/README.md +++ b/README.md @@ -173,3 +173,4 @@ licenses: - [accelerate-lapacke](https://github.com/lepus2589/accelerate-lapacke) - [LAPACK](https://github.com/Reference-LAPACK/lapack) - [TOML++](https://github.com/marzer/tomlplusplus) +- [json](https://github.com/nlohmann/json) From 4511ece708d82fdb77774120c69e5055bf0f04ac Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 11:14:09 -0500 Subject: [PATCH 02/61] update mlir: create ion json string and pass into device init kwargs; update tests accordingly --- mlir/lib/Ion/Transforms/CMakeLists.txt | 7 + .../lib/Ion/Transforms/ConversionPatterns.cpp | 251 ++++----------- mlir/test/Ion/IonOpLowering.mlir | 300 ++++++++++++------ mlir/test/Ion/ParallelProtocolOpLowering.mlir | 91 +----- mlir/test/Ion/PulseOpLowering.mlir | 2 +- 5 files changed, 297 insertions(+), 354 deletions(-) diff --git a/mlir/lib/Ion/Transforms/CMakeLists.txt b/mlir/lib/Ion/Transforms/CMakeLists.txt index a9756dd44f..dea7ce5daa 100644 --- a/mlir/lib/Ion/Transforms/CMakeLists.txt +++ b/mlir/lib/Ion/Transforms/CMakeLists.txt @@ -34,6 +34,13 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(tomlplusplus) +# Fetch json utilities +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_MakeAvailable(json) +target_link_libraries(ion-transforms + PRIVATE nlohmann_json::nlohmann_json +) + target_link_libraries(${LIBRARY_NAME} PRIVATE tomlplusplus::tomlplusplus) # tmol++ source has a warning which we want to ignore diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index ec92e08fbc..2e39977b63 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -12,14 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +#include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/IRMapping.h" #include "Ion/IR/IonOps.h" #include "Ion/Transforms/Patterns.h" -#include "mlir/IR/IRMapping.h" +#include "Quantum/IR/QuantumOps.h" using namespace mlir; using namespace catalyst::ion; +using namespace catalyst::quantum; +using json = nlohmann::json; namespace { @@ -42,38 +48,6 @@ LLVM::LLVMFuncOp ensureFunctionDeclaration(PatternRewriter &rewriter, Operation return cast(fnDecl); } -Value getGlobalString(Location loc, OpBuilder &rewriter, StringRef key, ModuleOp mod) -{ - StringRef value = StringRef(key.data(), key.size() + 1); - auto type = LLVM::LLVMArrayType::get(IntegerType::get(rewriter.getContext(), 8), value.size()); - LLVM::GlobalOp glb = mod.lookupSymbol(key); - if (!glb) { - OpBuilder::InsertionGuard guard(rewriter); // to reset the insertion point - rewriter.setInsertionPointToStart(mod.getBody()); - glb = rewriter.create(loc, type, true, LLVM::Linkage::Internal, key, - rewriter.getStringAttr(value)); - } - return rewriter.create(loc, LLVM::LLVMPointerType::get(rewriter.getContext()), - type, rewriter.create(loc, glb), - ArrayRef{0, 0}, true); -} - -LLVM::LLVMStructType createLevelStructType(MLIRContext *ctx) -{ - return LLVM::LLVMStructType::getLiteral( - ctx, { - LLVM::LLVMPointerType::get(ctx), // label - IntegerType::get(ctx, 64), // principal - Float64Type::get(ctx), // spin - Float64Type::get(ctx), // orbital - Float64Type::get(ctx), // nuclear - Float64Type::get(ctx), // spin_orbital - Float64Type::get(ctx), // spin_orbital_nuclear - Float64Type::get(ctx), // spin_orbital_nuclear_magnetization - Float64Type::get(ctx), // energy - }); -} - LLVM::LLVMStructType createBeamStructType(MLIRContext *ctx, OpBuilder &rewriter, BeamAttr &beamAttr) { return LLVM::LLVMStructType::getLiteral( @@ -88,94 +62,6 @@ LLVM::LLVMStructType createBeamStructType(MLIRContext *ctx, OpBuilder &rewriter, }); } -Value createLevelStruct(Location loc, OpBuilder &rewriter, MLIRContext *ctx, ModuleOp &mod, - LevelAttr &levelAttr, LLVM::LLVMStructType &levelStructType) -{ - Value levelStruct = rewriter.create(loc, levelStructType); - auto label = levelAttr.getLabel().getValue().str(); - auto labelGlobal = getGlobalString(loc, rewriter, label, mod); - std::vector fieldValues = { - labelGlobal, - rewriter.create(loc, rewriter.getI64Type(), levelAttr.getPrincipal()), - rewriter.create(loc, rewriter.getF64Type(), levelAttr.getSpin()), - rewriter.create(loc, rewriter.getF64Type(), levelAttr.getOrbital()), - rewriter.create(loc, rewriter.getF64Type(), levelAttr.getNuclear()), - rewriter.create(loc, rewriter.getF64Type(), levelAttr.getSpinOrbital()), - rewriter.create(loc, rewriter.getF64Type(), - levelAttr.getSpinOrbitalNuclear()), - rewriter.create(loc, rewriter.getF64Type(), - levelAttr.getSpinOrbitalNuclearMagnetization()), - rewriter.create(loc, rewriter.getF64Type(), levelAttr.getEnergy())}; - for (size_t i = 0; i < fieldValues.size(); i++) { - levelStruct = rewriter.create(loc, levelStruct, fieldValues[i], i); - } - return levelStruct; -} - -Value createLevelsArray(Location loc, OpBuilder &rewriter, MLIRContext *ctx, ModuleOp &mod, - ArrayAttr &levelsAttr) -{ - LLVM::LLVMStructType levelStructType = createLevelStructType(ctx); - Value levelsArray = rewriter.create( - loc, LLVM::LLVMArrayType::get(levelStructType, levelsAttr.size())); - - for (size_t i = 0; i < levelsAttr.size(); ++i) { - auto levelAttr = cast(levelsAttr[i]); - Value levelStruct = createLevelStruct(loc, rewriter, ctx, mod, levelAttr, levelStructType); - levelsArray = rewriter.create(loc, levelsArray, levelStruct, i); - } - Value levelArraySize = - rewriter.create(loc, rewriter.getI64IntegerAttr(levelsAttr.size())); - Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); - Value levelsArrayPtr = - rewriter.create(loc, /*resultType=*/ptrType, - /*elementType=*/levelsArray.getType(), levelArraySize); - rewriter.create(loc, levelsArray, levelsArrayPtr); - return levelsArrayPtr; -} - -Value createTransitionsArray(Location loc, OpBuilder &rewriter, MLIRContext *ctx, ModuleOp &mod, - ArrayAttr &transitionsAttr) -{ - auto transitionStructType = - LLVM::LLVMStructType::getLiteral(ctx, { - LLVM::LLVMPointerType::get(ctx), // level_0 - LLVM::LLVMPointerType::get(ctx), // level_1 - Float64Type::get(ctx), // einstein_a - }); - Value transitionsArray = rewriter.create( - loc, LLVM::LLVMArrayType::get(transitionStructType, transitionsAttr.size())); - - for (size_t i = 0; i < transitionsAttr.size(); ++i) { - auto transitionAttr = cast(transitionsAttr[i]); - Value transitionStruct = rewriter.create(loc, transitionStructType); - auto level0 = transitionAttr.getLevel_0().getValue().str(); - auto level1 = transitionAttr.getLevel_1().getValue().str(); - auto level0_global = getGlobalString(loc, rewriter, level0, mod); - auto level1_global = getGlobalString(loc, rewriter, level1, mod); - transitionStruct = - rewriter.create(loc, transitionStruct, level0_global, 0); - transitionStruct = - rewriter.create(loc, transitionStruct, level1_global, 1); - transitionStruct = rewriter.create( - loc, transitionStruct, - rewriter.create(loc, rewriter.getF64Type(), - transitionAttr.getEinsteinA()), - 2); - transitionsArray = - rewriter.create(loc, transitionsArray, transitionStruct, i); - } - - Value transitionsArraySize = - rewriter.create(loc, rewriter.getI64IntegerAttr(transitionsAttr.size())); - Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); - Value transitionsArrayPtr = rewriter.create( - loc, /*resultType=*/ptrType, - /*elementType=*/transitionsArray.getType(), transitionsArraySize); - rewriter.create(loc, transitionsArray, transitionsArrayPtr); - return transitionsArrayPtr; -} - Value createBeamStruct(Location loc, OpBuilder &rewriter, MLIRContext *ctx, BeamAttr &beamAttr) { Type beamStructType = createBeamStructType(ctx, rewriter, beamAttr); @@ -218,77 +104,78 @@ Value createBeamStruct(Location loc, OpBuilder &rewriter, MLIRContext *ctx, Beam struct IonOpPattern : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; + // Create the ion JSON and pass it into the device kwargs as a JSON string LogicalResult matchAndRewrite(catalyst::ion::IonOp op, catalyst::ion::IonOpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - Location loc = op.getLoc(); - MLIRContext *ctx = this->getContext(); - ModuleOp mod = op->getParentOfType(); - const TypeConverter *conv = getTypeConverter(); + func::FuncOp funcOp = op->getParentOfType(); - Type IonTy = conv->convertType(IonType::get(ctx)); - Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); - Value c1 = rewriter.create(loc, rewriter.getI64IntegerAttr(1)); + DeviceInitOp deviceInitOp = *funcOp.getOps().begin(); + StringRef deviceKwargs = deviceInitOp.getKwargs(); - // Extract relevant ion properties - auto nameStr = op.getName().getValue().str(); - auto name = getGlobalString(loc, rewriter, nameStr, mod); - auto mass = rewriter.create(loc, op.getMass()); - auto charge = rewriter.create(loc, op.getCharge()); auto positionAttr = op.getPosition(); auto levelsAttr = op.getLevels(); auto transitionsAttr = op.getTransitions(); - Value levelsArrayPtr = createLevelsArray(loc, rewriter, ctx, mod, levelsAttr); - - Value transitionsArrayPtr = - createTransitionsArray(loc, rewriter, ctx, mod, transitionsAttr); - - // Define the function signature for the Ion stub - Type ionStructType = LLVM::LLVMStructType::getLiteral( - ctx, { - ptrType, // name - Float64Type::get(ctx), // mass - Float64Type::get(ctx), // charge - LLVM::LLVMArrayType::get( // position - rewriter.getF64Type(), positionAttr.size()), - ptrType, // levels - IntegerType::get(ctx, 64), // number of levels - ptrType, // Transitions - IntegerType::get(ctx, 64), // number of Transitions - }); - - // Create an instance of the Ion struct - Value ionStruct = rewriter.create(loc, ionStructType); - ionStruct = rewriter.create(loc, ionStruct, name, 0); - ionStruct = rewriter.create(loc, ionStruct, mass, 1); - ionStruct = rewriter.create(loc, ionStruct, charge, 2); - for (size_t i = 0; i < positionAttr.size(); i++) { - Value posConst = rewriter.create( - loc, rewriter.getF64Type(), - rewriter.getFloatAttr(rewriter.getF64Type(), positionAttr[i])); - ionStruct = rewriter.create( - loc, ionStruct, posConst, ArrayRef({3, static_cast(i)})); + json ion_json = R"({ + "class_": "Ion", + "levels": [], + "transitions" : [] +})"_json; + ion_json["mass"] = op.getMass().getValue().convertToDouble(); + ion_json["charge"] = op.getCharge().getValueAsDouble(); + + assert(positionAttr.size() == 3 && "Position must have 3 coordinates!"); + std::array position = {positionAttr[0], positionAttr[1], positionAttr[2]}; + ion_json["position"] = position; + + std::map LevelLabel2Index; + for (size_t i = 0; i < levelsAttr.size(); i++) { + auto levelAttr = cast(levelsAttr[i]); + + json this_level = + json{{"class_", "Level"}, + {"principal", levelAttr.getPrincipal().getInt()}, + {"spin", levelAttr.getSpin().getValue().convertToDouble()}, + {"orbital", levelAttr.getOrbital().getValue().convertToDouble()}, + {"nuclear", levelAttr.getNuclear().getValue().convertToDouble()}, + {"spin_orbital", levelAttr.getSpinOrbital().getValue().convertToDouble()}, + {"spin_orbital_nuclear", + levelAttr.getSpinOrbitalNuclear().getValue().convertToDouble()}, + {"spin_orbital_nuclear_magnetization", + levelAttr.getSpinOrbitalNuclearMagnetization().getValue().convertToDouble()}, + {"energy", levelAttr.getEnergy().getValue().convertToDouble()}, + {"label", levelAttr.getLabel().getValue().str()}}; + + ion_json["levels"].push_back(this_level); + LevelLabel2Index[levelAttr.getLabel().getValue().str()] = i; } - ionStruct = rewriter.create(loc, ionStruct, levelsArrayPtr, 4); - ionStruct = rewriter.create( - loc, ionStruct, - rewriter.create(loc, rewriter.getI64Type(), levelsAttr.size()), 5); - ionStruct = rewriter.create(loc, ionStruct, transitionsArrayPtr, 6); - ionStruct = rewriter.create( - loc, ionStruct, - rewriter.create(loc, rewriter.getI64Type(), transitionsAttr.size()), - 7); - Value ionStructPtr = rewriter.create(loc, /*resultType=*/ptrType, - /*elementType=*/ionStructType, c1); - rewriter.create(loc, ionStruct, ionStructPtr); - // Create the Ion stub function - Type qirSignature = LLVM::LLVMFunctionType::get(IonTy, ptrType); - std::string qirName = "__catalyst_ion"; - LLVM::LLVMFuncOp fnDecl = ensureFunctionDeclaration(rewriter, op, qirName, qirSignature); - rewriter.replaceOpWithNewOp(op, fnDecl, ionStructPtr); + for (size_t i = 0; i < transitionsAttr.size(); i++) { + auto transitionAttr = cast(transitionsAttr[i]); + + std::string level0_label = transitionAttr.getLevel_0().getValue().str(); + std::string level1_label = transitionAttr.getLevel_1().getValue().str(); + + assert(LevelLabel2Index.count(level0_label) == 1 + && LevelLabel2Index.count(level1_label) == 1 + && "A transition level's label must refer to an existing level in the ion!"); + + const json &level1 = + ion_json["levels"][LevelLabel2Index[level0_label]]; + const json &level2 = + ion_json["levels"][LevelLabel2Index[level1_label]]; + + json this_transition = + json{{"class_", "Transition"}, + {"einsteinA", transitionAttr.getEinsteinA().getValue().convertToDouble()}, + {"level1", level1}, + {"level2", level2}}; + ion_json["transitions"].push_back(this_transition); + } + deviceInitOp.setKwargs(deviceKwargs.str() + "ION:" + std::string(ion_json.dump())); + rewriter.eraseOp(op); return success(); } }; @@ -360,7 +247,7 @@ struct ParallelProtocolOpPattern : public OpConversionPatternconvertType(IonType::get(ctx)); Type protocolFuncType = LLVM::LLVMFunctionType::get(protocolResultType, {ptrType, pulseArraySize.getType()}); - std::string protocolFuncName = "__catalyst_parallel_protocol"; + std::string protocolFuncName = "__catalyst__oqd__ParallelProtocol"; LLVM::LLVMFuncOp protocolFnDecl = ensureFunctionDeclaration(rewriter, op, protocolFuncName, protocolFuncType); rewriter.replaceOpWithNewOp(op, protocolFnDecl, operands); @@ -398,7 +285,7 @@ struct PulseOpPattern : public OpConversionPattern { conv->convertType(PulseType::get(ctx)), {conv->convertType(qubitTy), time.getType(), Float64Type::get(ctx), LLVM::LLVMPointerType::get(rewriter.getContext())}); - std::string qirName = "__catalyst_pulse"; + std::string qirName = "__catalyst__oqd__pulse"; LLVM::LLVMFuncOp fnDecl = ensureFunctionDeclaration(rewriter, op, qirName, qirSignature); rewriter.replaceOpWithNewOp(op, fnDecl, operands); diff --git a/mlir/test/Ion/IonOpLowering.mlir b/mlir/test/Ion/IonOpLowering.mlir index d5a1cb6023..5a1b34a087 100644 --- a/mlir/test/Ion/IonOpLowering.mlir +++ b/mlir/test/Ion/IonOpLowering.mlir @@ -14,119 +14,233 @@ // RUN: quantum-opt %s --convert-ion-to-llvm --split-input-file -verify-diagnostics | FileCheck %s -// CHECK: llvm.mlir.global internal constant @upstate("upstate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @estate("estate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @downstate("downstate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @Yb171("Yb171\00") {addr_space = 0 : i32} - + // CHECK-LABEL: ion_op func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {diff_method = "parameter-shift", llvm.linkage = #llvm.linkage, qnode} { - // Ensure constants are correctly defined - // CHECK: %[[const_1:.*]] = llvm.mlir.constant(1 : i64) - // CHECK: %[[addr_of_yb171:.*]] = llvm.mlir.addressof @Yb171 : !llvm.ptr - // CHECK: %[[ptr_to_yb171:.*]] = llvm.getelementptr inbounds %[[addr_of_yb171]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<6 x i8> - // CHECK: %[[const_mass:.*]] = llvm.mlir.constant(1.710000e+02 : f64) - // CHECK: %[[const_charge:.*]] = llvm.mlir.constant(1.000000e+00 : f64) - - // Check level array initialization - // CHECK: %[[level_array_undef:.*]] = llvm.mlir.undef : !llvm.array<3 x struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)>> - - // Level 0 - // CHECK: %[[level_struct_0_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)> - // CHECK: llvm.mlir.addressof @downstate - - // Level 1 - // CHECK: %[[level_struct_1_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)> - // llvm.mlir.addressof @estate : !llvm.ptr - - // Level 2 - // CHECK: %[[level_struct_2_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)> - // CHECK: llvm.mlir.addressof @upstate : !llvm.ptr - // Levels Array - // CHECK: %[[levels_array_size:.*]] = llvm.mlir.constant(3 : i64) : i64 - // CHECK: %[[levels_array_ptr:.*]] = llvm.alloca %[[levels_array_size:.*]] x !llvm.array<3 x struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)>> : (i64) -> !llvm.ptr - // CHECK: llvm.store %[[levels_array:.*]], %[[levels_array_ptr:.*]] : !llvm.array<3 x struct<(ptr, i64, f64, f64, f64, f64, f64, f64, f64)>>, !llvm.ptr - - // Transition array initialization - // CHECK: llvm.mlir.undef : !llvm.array<3 x struct<(ptr, ptr, f64)>> + %c0_i64 = arith.constant 0 : i64 + quantum.device shots(%c0_i64) ["blah.so", "OQD", "{'shots': 0, 'mcmc': False}"] - // Transition 1 - // CHECK: %[[transition_1_struct_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, f64)> - // CHECK: llvm.mlir.addressof @downstate - // CHECK: llvm.mlir.addressof @estate +// CHECK: quantum.device +// CHECK-SAME: ["blah.so", "OQD", "{'shots': 0, 'mcmc': False}ION: +// COM: nlohmann-json library dumps double quotation literals in json strings as \22 +// COM: nlohmann-json library dumps JSON specs in alphabetical order +// CHECK-SAME: { +// CHECK-SAME: \22charge\22:1.0, +// CHECK-SAME: \22class_\22:\22Ion\22, +// CHECK-SAME: \22levels\22:[ +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:0.0, +// CHECK-SAME: \22label\22:\22l0\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:0.0, +// CHECK-SAME: \22principal\22:6, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:0.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:0.0 +// CHECK-SAME: }, +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:62.83185307179586, +// CHECK-SAME: \22label\22:\22l1\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:0.0, +// CHECK-SAME: \22principal\22:6, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:0.0 +// CHECK-SAME: }, +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:628.3185307179587, +// CHECK-SAME: \22label\22:\22l2\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:1.0, +// CHECK-SAME: \22principal\22:5, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:-1.0 +// CHECK-SAME: }, +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:1256.6370614359173, +// CHECK-SAME: \22label\22:\22l3\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:1.0, +// CHECK-SAME: \22principal\22:5, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:1.0 +// CHECK-SAME: } +// CHECK-SAME: ], +// CHECK-SAME: \22mass\22:171.0, +// CHECK-SAME: \22position\22:[1.0,2.0,-1.0], +// CHECK-SAME: \22transitions\22:[ +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Transition\22, +// CHECK-SAME: \22einsteinA\22:2.2, +// CHECK-SAME: \22level1\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:0.0, +// CHECK-SAME: \22label\22:\22l0\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:0.0, +// CHECK-SAME: \22principal\22:6, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:0.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:0.0 +// CHECK-SAME: }, +// CHECK-SAME: \22level2\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:628.3185307179587, +// CHECK-SAME: \22label\22:\22l2\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:1.0, +// CHECK-SAME: \22principal\22:5, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:-1.0 +// CHECK-SAME: } +// CHECK-SAME: }, +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Transition\22, +// CHECK-SAME: \22einsteinA\22:1.1, +// CHECK-SAME: \22level1\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:62.83185307179586, +// CHECK-SAME: \22label\22:\22l1\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:0.0, +// CHECK-SAME: \22principal\22:6, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:0.0 +// CHECK-SAME: }, +// CHECK-SAME: \22level2\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:628.3185307179587, +// CHECK-SAME: \22label\22:\22l2\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:1.0, +// CHECK-SAME: \22principal\22:5, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:-1.0 +// CHECK-SAME: } +// CHECK-SAME: }, +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Transition\22, +// CHECK-SAME: \22einsteinA\22:3.3, +// CHECK-SAME: \22level1\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:0.0, +// CHECK-SAME: \22label\22:\22l0\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:0.0, +// CHECK-SAME: \22principal\22:6, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:0.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:0.0 +// CHECK-SAME: }, +// CHECK-SAME: \22level2\22: +// CHECK-SAME: { +// CHECK-SAME: \22class_\22:\22Level\22, +// CHECK-SAME: \22energy\22:1256.6370614359173, +// CHECK-SAME: \22label\22:\22l3\22, +// CHECK-SAME: \22nuclear\22:0.5, +// CHECK-SAME: \22orbital\22:1.0, +// CHECK-SAME: \22principal\22:5, +// CHECK-SAME: \22spin\22:0.5, +// CHECK-SAME: \22spin_orbital\22:0.5, +// CHECK-SAME: \22spin_orbital_nuclear\22:1.0, +// CHECK-SAME: \22spin_orbital_nuclear_magnetization\22:1.0 +// CHECK-SAME: } +// CHECK-SAME: } +// CHECK-SAME: ] +// CHECK-SAME: } +// CHECK-SAME: "] - // Transition 2 - // CHECK: %[[transition_2_struct_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, f64)> - // CHECK: llvm.mlir.addressof @downstate - // CHECK: llvm.mlir.addressof @upstate - - // Transition 3 - // CHECK: %[[transition_3_struct_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, f64)> - // CHECK: llvm.mlir.addressof @estate - // CHECK: llvm.mlir.addressof @upstate - - // Final Ion Struct - // CHECK: %[[ion_struct_undef:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, f64, f64, array<3 x f64>, ptr, i64, ptr, i64)> - // CHECK: %[[ion_name_ptr:.*]] = llvm.insertvalue %[[ptr_to_yb171]], %[[ion_struct_undef]][0] : !llvm.struct<(ptr, f64, f64, array<3 x f64>, ptr, i64, ptr, i64)> - // CHECK: %[[ion_mass_ptr:.*]] = llvm.insertvalue %[[const_mass]], %[[ion_name_ptr]][1] : !llvm.struct<(ptr, f64, f64, array<3 x f64>, ptr, i64, ptr, i64)> - // CHECK: %[[ion_charge_ptr:.*]] = llvm.insertvalue %[[const_charge]], %[[ion_mass_ptr]][2] : !llvm.struct<(ptr, f64, f64, array<3 x f64>, ptr, i64, ptr, i64)> - // CHECK: %[[ion_ptr:.*]] = llvm.call @__catalyst_ion(%{{.*}}) : (!llvm.ptr) -> !llvm.ptr %0 = ion.ion { - charge = 1.000000e+00 : f64, - mass = 1.710000e+02 : f64, - name = "Yb171", + charge = 1.000000e+00 : f64, + mass = 1.710000e+02 : f64, + name = "Yb171", position = array, levels = [ #ion.level< - label="downstate", - principal = 6 : i64, - spin = 4.000000e-01 : f64, - orbital = 5.000000e-01 : f64, - nuclear = 6.000000e-01 : f64, - spin_orbital = 8.000000e-01 : f64, - spin_orbital_nuclear = 9.000000e-01 : f64, - spin_orbital_nuclear_magnetization = 1.000000e+00 : f64, + label="l0", + principal = 6 : i64, + spin = 5.000000e-01 : f64, + orbital = 0.000000e+00 : f64, + nuclear = 5.000000e-01 : f64, + spin_orbital = 5.000000e-01 : f64, + spin_orbital_nuclear = 0.000000e+00 : f64, + spin_orbital_nuclear_magnetization = 0.000000e+00 : f64, energy = 0.000000e+00 : f64 - >, + >, + #ion.level< + label="l1", + principal = 6 : i64, + spin = 5.000000e-01 : f64, + orbital = 0.000000e+00 : f64, + nuclear = 5.000000e-01 : f64, + spin_orbital = 5.000000e-01 : f64, + spin_orbital_nuclear = 1.000000e+00 : f64, + spin_orbital_nuclear_magnetization = 0.000000e+00 : f64, + energy = 62.83185307179586 : f64 + >, #ion.level< - label="estate", - principal = 6 : i64, - spin = 1.400000e+00 : f64, - orbital = 1.500000e+00 : f64, - nuclear = 1.600000e+00 : f64, - spin_orbital = 1.800000e+00 : f64, - spin_orbital_nuclear = 1.900000e+00 : f64, - spin_orbital_nuclear_magnetization = 2.000000e+00 : f64, - energy = 1.264300e+10 : f64 - >, + label="l2", + principal = 5 : i64, + spin = 5.000000e-01 : f64, + orbital = 1.000000e+00 : f64, + nuclear = 5.000000e-01 : f64, + spin_orbital = 5.000000e-01 : f64, + spin_orbital_nuclear = 1.000000e+00 : f64, + spin_orbital_nuclear_magnetization = -1.000000e+00 : f64, + energy = 628.3185307179587 : f64 + >, #ion.level< - label="upstate", - principal = 5 : i64, - spin = 2.400000e+00 : f64, - orbital = 2.500000e+00 : f64, - nuclear = 2.600000e+00 : f64, - spin_orbital = 2.800000e+00 : f64, - spin_orbital_nuclear = 2.900000e+00 : f64, - spin_orbital_nuclear_magnetization = 3.000000e+00 : f64, - energy = 8.115200e+14 : f64 + label="l3", + principal = 5 : i64, + spin = 5.000000e-01 : f64, + orbital = 1.000000e+00 : f64, + nuclear = 5.000000e-01 : f64, + spin_orbital = 5.000000e-01 : f64, + spin_orbital_nuclear = 1.000000e+00 : f64, + spin_orbital_nuclear_magnetization = 1.000000e+00 : f64, + energy = 1256.6370614359173 : f64 > - ], + ], transitions = [ #ion.transition< - level_0 = "downstate", - level_1 = "estate", + level_0 = "l0", + level_1 = "l2", einstein_a = 2.200000e+00 : f64 - >, + >, #ion.transition< - level_0 = "downstate", - level_1 = "upstate", + level_0 = "l1", + level_1 = "l2", einstein_a = 1.100000e+00 : f64 - >, + >, #ion.transition< - level_0 = "estate", - level_1 = "upstate", + level_0 = "l0", + level_1 = "l3", einstein_a = 3.300000e+00 : f64 > ] diff --git a/mlir/test/Ion/ParallelProtocolOpLowering.mlir b/mlir/test/Ion/ParallelProtocolOpLowering.mlir index 8afc7f4d0a..64ecf699e0 100644 --- a/mlir/test/Ion/ParallelProtocolOpLowering.mlir +++ b/mlir/test/Ion/ParallelProtocolOpLowering.mlir @@ -14,97 +14,32 @@ // RUN: quantum-opt %s --convert-ion-to-llvm --split-input-file -verify-diagnostics | FileCheck %s -// CHECK: llvm.func @__catalyst_pulse(!llvm.ptr, f64, f64, !llvm.ptr) -> !llvm.ptr -// CHECK: llvm.func @__catalyst_parallel_protocol(!llvm.ptr, i64) -> !llvm.ptr -// CHECK: llvm.func @__catalyst_ion(!llvm.ptr) -> !llvm.ptr -// CHECK: llvm.mlir.global internal constant @upstate("upstate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @estate("estate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @downstate("downstate\00") {addr_space = 0 : i32} -// CHECK: llvm.mlir.global internal constant @Yb171("Yb171\00") {addr_space = 0 : i32} - +// CHECK: llvm.func @__catalyst__oqd__pulse(!llvm.ptr, f64, f64, !llvm.ptr) -> !llvm.ptr +// CHECK: llvm.func @__catalyst__oqd__ParallelProtocol(!llvm.ptr, i64) -> !llvm.ptr + // CHECK-LABEL: parallel_protocol_op func.func public @parallel_protocol_op(%arg0: f64) -> !quantum.bit { - // Ion - // CHECK: %[[ion:.*]] = llvm.call @__catalyst_ion // Pulse 1 - // CHECK: %[[pulse_1:.*]] = llvm.call @__catalyst_pulse - + // CHECK: %[[pulse_1:.*]] = llvm.call @__catalyst__oqd__pulse + // Pulse 2 - // CHECK: %[[pulse_2:.*]] = llvm.call @__catalyst_pulse + // CHECK: %[[pulse_2:.*]] = llvm.call @__catalyst__oqd__pulse // Pulse array // CHECK: %[[pulse_array:.*]] = llvm.mlir.undef : !llvm.array<2 x ptr> - // CHECK: %[[pulse_array_insert_0:.*]] = llvm.insertvalue %[[pulse_1_ptr:.*]], %[[pulse_array:.*]][0] : !llvm.array<2 x ptr> - // CHECK: %[[pulse_array_insert_1:.*]] = llvm.insertvalue %[[pulse_2_ptr:.*]], %[[pulse_array:.*]][1] : !llvm.array<2 x ptr> - - // Store pulse array on stack + // CHECK: %[[pulse_array_insert_0:.*]] = llvm.insertvalue %[[pulse_1_ptr:.*]], %[[pulse_array:.*]][0] : !llvm.array<2 x ptr> + // CHECK: %[[pulse_array_insert_1:.*]] = llvm.insertvalue %[[pulse_2_ptr:.*]], %[[pulse_array:.*]][1] : !llvm.array<2 x ptr> + + // Store pulse array on stack // CHECK: %[[c1:.*]] = llvm.mlir.constant(1 : i64) : i64 // CHECK: %[[pulse_array_ptr:.*]] = llvm.alloca %[[c1:.*]] x !llvm.array<2 x ptr> : (i64) -> !llvm.ptr // CHECK: llvm.store %[[pulse_array_insert_1:.*]], %[[pulse_array_ptr:.*]] : !llvm.array<2 x ptr>, !llvm.ptr // Parallel Protocol Stub // CHECK: %[[pulse_array_size:.*]] = llvm.mlir.constant(2 : i64) : i64 - // CHECK: %[[pp:.*]] = llvm.call @__catalyst_parallel_protocol(%[[pulse_array_ptr:.*]], %[[pulse_array_size:.*]]) : (!llvm.ptr, i64) -> !llvm.ptr - - %ion = ion.ion { - charge = 1.000000e+00 : f64, - mass = 1.710000e+02 : f64, - name = "Yb171", - position = array, - levels = [ - #ion.level< - label="downstate", - principal = 6 : i64, - spin = 4.000000e-01 : f64, - orbital = 5.000000e-01 : f64, - nuclear = 6.000000e-01 : f64, - spin_orbital = 8.000000e-01 : f64, - spin_orbital_nuclear = 9.000000e-01 : f64, - spin_orbital_nuclear_magnetization = 1.000000e+00 : f64, - energy = 0.000000e+00 : f64 - >, - #ion.level< - label="estate", - principal = 6 : i64, - spin = 1.400000e+00 : f64, - orbital = 1.500000e+00 : f64, - nuclear = 1.600000e+00 : f64, - spin_orbital = 1.800000e+00 : f64, - spin_orbital_nuclear = 1.900000e+00 : f64, - spin_orbital_nuclear_magnetization = 2.000000e+00 : f64, - energy = 1.264300e+10 : f64 - >, - #ion.level< - label="upstate", - principal = 5 : i64, - spin = 2.400000e+00 : f64, - orbital = 2.500000e+00 : f64, - nuclear = 2.600000e+00 : f64, - spin_orbital = 2.800000e+00 : f64, - spin_orbital_nuclear = 2.900000e+00 : f64, - spin_orbital_nuclear_magnetization = 3.000000e+00 : f64, - energy = 8.115200e+14 : f64 - > - ], - transitions = [ - #ion.transition< - level_0 = "downstate", - level_1 = "estate", - einstein_a = 2.200000e+00 : f64 - >, - #ion.transition< - level_0 = "downstate", - level_1 = "upstate", - einstein_a = 1.100000e+00 : f64 - >, - #ion.transition< - level_0 = "estate", - level_1 = "upstate", - einstein_a = 3.300000e+00 : f64 - > - ] - } : !ion.ion + // CHECK: %[[pp:.*]] = llvm.call @__catalyst__oqd__ParallelProtocol(%[[pulse_array_ptr:.*]], %[[pulse_array_size:.*]]) : (!llvm.ptr, i64) -> !llvm.ptr + %qreg = quantum.alloc( 1) : !quantum.reg %q0 = quantum.extract %qreg[ 0] : !quantum.reg -> !quantum.bit @@ -121,7 +56,7 @@ func.func public @parallel_protocol_op(%arg0: f64) -> !quantum.bit { >, phase=0.0 } : !ion.pulse - + %p2 = ion.pulse(%arg0: f64) %arg1 { beam=#ion.beam< transition_index=0, diff --git a/mlir/test/Ion/PulseOpLowering.mlir b/mlir/test/Ion/PulseOpLowering.mlir index 1b65024790..591b91bede 100644 --- a/mlir/test/Ion/PulseOpLowering.mlir +++ b/mlir/test/Ion/PulseOpLowering.mlir @@ -44,7 +44,7 @@ func.func @pulse_op(%arg0: f64) -> !quantum.bit { // CHECK: %[[c1:.*]] = llvm.mlir.constant(1 : i64) : i64 // CHECK: %[[beam_ptr:.*]] = llvm.alloca %[[c1:.*]] x !llvm.struct<(i64, f64, f64, array<2 x i64>, array<2 x i64>)> : (i64) -> !llvm.ptr // CHECK: llvm.store %[[beam_struct_wavevector_1:.*]], %[[beam_ptr:.*]] : !llvm.struct<(i64, f64, f64, array<2 x i64>, array<2 x i64>)>, !llvm.ptr - // CHECK: %[[pulse:.*]] = llvm.call @__catalyst_pulse(%[[qubit_ptr:.*]], %arg0, %[[phase:.*]], %[[beam_struct_wavevector_1:.*]]) : (!llvm.ptr, f64, f64, !llvm.ptr) -> !llvm.ptr + // CHECK: %[[pulse:.*]] = llvm.call @__catalyst__oqd__pulse(%[[qubit_ptr:.*]], %arg0, %[[phase:.*]], %[[beam_struct_wavevector_1:.*]]) : (!llvm.ptr, f64, f64, !llvm.ptr) -> !llvm.ptr %0 = quantum.alloc( 1) : !quantum.reg %1 = quantum.extract %0[0] : !quantum.reg -> !quantum.bit From cd2eef6e05924f01d229f3c01747fe5e685e4de7 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 12:03:35 -0500 Subject: [PATCH 03/61] add oqd runtime stubs, tests and build system --- runtime/Makefile | 2 +- runtime/include/OQDRuntimeCAPI.h | 54 ++ runtime/lib/CMakeLists.txt | 4 + runtime/lib/OQDcapi/CMakeLists.txt | 43 ++ runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp | 122 ++++ runtime/lib/backend/oqd/CMakeLists.txt | 4 + runtime/lib/backend/oqd/OQDDevice.cpp | 15 +- runtime/lib/backend/oqd/OQDDevice.hpp | 16 +- runtime/tests/CMakeLists.txt | 2 + runtime/tests/Test_OQDDevice.cpp | 838 ++++++++++++++++++++++++- 10 files changed, 1094 insertions(+), 6 deletions(-) create mode 100644 runtime/include/OQDRuntimeCAPI.h create mode 100644 runtime/lib/OQDcapi/CMakeLists.txt create mode 100644 runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp diff --git a/runtime/Makefile b/runtime/Makefile index 69fa0093b2..397ccac7f7 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -27,7 +27,7 @@ ifeq ($(ENABLE_OPENQASM), ON) endif ifeq ($(ENABLE_OQD), ON) - BUILD_TARGETS += rtd_oqd_device + BUILD_TARGETS += rt_OQD_capi rtd_oqd_device TEST_TARGETS += runner_tests_oqd endif diff --git a/runtime/include/OQDRuntimeCAPI.h b/runtime/include/OQDRuntimeCAPI.h new file mode 100644 index 0000000000..68d3de09c8 --- /dev/null +++ b/runtime/include/OQDRuntimeCAPI.h @@ -0,0 +1,54 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#ifndef OQDRUNTIMECAPI_H +#define OQDRUNTIMECAPI_H + +#include +#include + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Beam { + int64_t transition_index; + double rabi; + double detuning; + std::array polarization; + std::array wavevector; +}; + +struct Pulse { + Beam *beam; + size_t target; + double duration; + double phase; +}; + +// OQD Runtime Instructions +void __catalyst__oqd__rt__initialize(); +void __catalyst__oqd__rt__finalize(); +void __catalyst__oqd__ion(const std::string &ion_specs); +Pulse *__catalyst__oqd__pulse(QUBIT *qubit, double duration, double phase, Beam *beam); +void __catalyst__oqd__ParallelProtocol(Pulse **pulses, size_t n); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/runtime/lib/CMakeLists.txt b/runtime/lib/CMakeLists.txt index 50fd0b0e75..70ed9bffbd 100644 --- a/runtime/lib/CMakeLists.txt +++ b/runtime/lib/CMakeLists.txt @@ -1,3 +1,7 @@ add_subdirectory(capi) add_subdirectory(backend) add_subdirectory(registry) + +if(ENABLE_OQD) +add_subdirectory(OQDcapi) +endif() diff --git a/runtime/lib/OQDcapi/CMakeLists.txt b/runtime/lib/OQDcapi/CMakeLists.txt new file mode 100644 index 0000000000..64c3c3deae --- /dev/null +++ b/runtime/lib/OQDcapi/CMakeLists.txt @@ -0,0 +1,43 @@ +################################## +# Object Lib catalyst_oqd_obj +################################## + +add_library(catalyst_oqd_obj OBJECT OQDRuntimeCAPI.cpp) + +# Fetch json utilities +include(FetchContent) +FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_MakeAvailable(json) + +# link to rt_backend and json utils +target_link_libraries(catalyst_oqd_obj + PUBLIC ${CMAKE_DL_LIBS} + PRIVATE nlohmann_json::nlohmann_json +) + +target_include_directories(catalyst_oqd_obj PUBLIC . + ${CMAKE_CURRENT_SOURCE_DIR} + ${runtime_includes} +) + +set_property(TARGET catalyst_oqd_obj PROPERTY POSITION_INDEPENDENT_CODE ON) + +##################### +# Shared Lib rt_OQD_capi +##################### + +add_library(rt_OQD_capi SHARED) + +target_link_libraries(rt_OQD_capi ${CMAKE_DL_LIBS} catalyst_oqd_obj) + +target_include_directories(rt_OQD_capi PUBLIC . + ${CMAKE_CURRENT_SOURCE_DIR} + ${runtime_includes} + ${capi_utils_includes} +) + +if(NOT APPLE) + set_property(TARGET rt_OQD_capi APPEND PROPERTY BUILD_RPATH $ORIGIN) +else() + set_property(TARGET rt_OQD_capi APPEND PROPERTY BUILD_RPATH @loader_path) +endif() diff --git a/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp b/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp new file mode 100644 index 0000000000..e0bf9be005 --- /dev/null +++ b/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp @@ -0,0 +1,122 @@ +// Copyright 2025 Xanadu Quantum Technologies Inc. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // std::reference_wrapper +#include +#include +#include + +#include + +#include "OQDRuntimeCAPI.h" + +using json = nlohmann::json; + +static std::unique_ptr JSON = nullptr; +static std::unique_ptr> PulseGarbageCan = nullptr; + +template json &numerical_json_factory(T value) +{ + static json j; + j["class_"] = "MathNum"; + j["value"] = value; + return j; +} + +void to_json(json &j, const Pulse &p) +{ + j = json{{"class_", "Pulse"}, {"duration", p.duration}}; + + json j_beam; + j_beam["class_"] = "Beam"; + j_beam["target"] = p.target; + j_beam["polarization"] = p.beam->polarization; + j_beam["wavevector"] = p.beam->wavevector; + j_beam["rabi"] = numerical_json_factory(p.beam->rabi); + j_beam["detuning"] = numerical_json_factory(p.beam->detuning); + j_beam["phase"] = numerical_json_factory(p.phase); + + const auto &transitions = (*JSON)["system"]["ions"][p.target]["transitions"]; + j_beam["transition"] = transitions[p.beam->transition_index]; + + j["beam"] = j_beam; +} + +extern "C" { + +void __catalyst__oqd__rt__initialize() +{ + PulseGarbageCan = std::make_unique>(); + + JSON = std::make_unique(); + (*JSON)["class_"] = "AtomicCircuit"; + + json system = R"({ + "class_": "System", + "ions": [] +})"_json; + (*JSON)["system"] = system; + + // The main openapl program is a sequential protocol + // Each gate is a parallel protocol in the main sequential protocol + json protocol = R"({ + "class_": "SequentialProtocol", + "sequence": [] +})"_json; + (*JSON)["protocol"] = protocol; +} + +void __catalyst__oqd__rt__finalize() +{ + for (auto pulse : *PulseGarbageCan) { + delete pulse; + } + + std::ofstream out_json("__openapl__output.json"); + out_json << JSON->dump(2); + JSON = nullptr; +} + +void __catalyst__oqd__ion(const std::string &ion_specs) +{ + (*JSON)["system"]["ions"].push_back(json::parse(ion_specs)); +} + +Pulse *__catalyst__oqd__pulse(QUBIT *qubit, double duration, double phase, Beam *beam) +{ + size_t wire = reinterpret_cast(qubit); + + // Since this is CAPI, we cannot return smart pointer. + // This means we have to new and delete manually. + Pulse *pulse = new Pulse({beam, wire, duration, phase}); + PulseGarbageCan->push_back(pulse); + return pulse; +} + +void __catalyst__oqd__ParallelProtocol(Pulse **pulses, size_t num_of_pulses) +{ + json j; + j["class_"] = "ParallelProtocol"; + + std::vector> pulses_json; + for (std::size_t i = 0; i < num_of_pulses; i++) { + pulses_json.push_back(std::ref(*(pulses[i]))); + } + j["sequence"] = pulses_json; + + (*JSON)["protocol"]["sequence"].push_back(j); +} + +} // extern "C" diff --git a/runtime/lib/backend/oqd/CMakeLists.txt b/runtime/lib/backend/oqd/CMakeLists.txt index cbae647dcd..eca64cce40 100644 --- a/runtime/lib/backend/oqd/CMakeLists.txt +++ b/runtime/lib/backend/oqd/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.20) project(rtd_oqd_device LANGUAGES CXX) +message(STATUS "Building the OQD device.") + add_library(rtd_oqd_device SHARED OQDDevice.cpp) set(CMAKE_CXX_STANDARD 20) @@ -14,3 +16,5 @@ target_include_directories(rtd_oqd_device PUBLIC ) set_property(TARGET rtd_oqd_device PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_link_libraries(rtd_oqd_device PRIVATE rt_OQD_capi) diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index fdea8c65f1..5a36d71a90 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -12,16 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "OQDDevice.hpp" +#include "OQDRuntimeCAPI.h" namespace Catalyst::Runtime::Device { auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector { - RT_FAIL("Unsupported functionality"); + for (size_t i = 0; i < num_qubits; i++) { + __catalyst__oqd__ion(this->ion_specs); + } + + // need to return a vector from 0 to num_qubits + std::vector result(num_qubits); + std::generate_n(result.begin(), num_qubits, + []() { static size_t i=0; return i++; }); + return result; } -void OQDDevice::ReleaseAllQubits() { RT_FAIL("Unsupported functionality"); } +void OQDDevice::ReleaseAllQubits() { this->ion_specs=""; } void OQDDevice::ReleaseQubit([[maybe_unused]] QubitIdType q) { diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index 4129ad3cfa..ef3ca4e003 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -20,6 +20,7 @@ #include #include +#include "OQDRuntimeCAPI.h" #include "QuantumDevice.hpp" // catalyst/runtime/lib/backend/common/ @@ -43,6 +44,7 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { Catalyst::Runtime::CacheManager> cache_manager{}; bool tape_recording{false}; size_t device_shots; + std::string ion_specs; std::unordered_map device_kwargs; @@ -58,13 +60,23 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { public: explicit OQDDevice(const std::string &kwargs = "{device_type : oqd, backend : default}") { - device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs); + __catalyst__oqd__rt__initialize(); + + // The OQD kwarg string format is: + // deviceKwargs.str() + "ION:" + std::string(ion_json.dump()) + // where deviceKwargs us the usual kwargs like {'shots': 0, 'mcmc': False} + // and ion_json is a JSON spec string for the ion + std::string ion_token = "ION:"; + size_t ion_token_pos = kwargs.find(ion_token); + ion_specs = kwargs.substr(ion_token_pos+ion_token.length()); + + device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs.substr(0, ion_token_pos)); device_shots = device_kwargs.contains("shots") ? static_cast(std::stoll(device_kwargs["shots"])) : 0; runner = std::make_unique(); } - ~OQDDevice() = default; + ~OQDDevice() { __catalyst__oqd__rt__finalize(); }; QUANTUM_DEVICE_DEL_DECLARATIONS(OQDDevice); diff --git a/runtime/tests/CMakeLists.txt b/runtime/tests/CMakeLists.txt index 5b08f8a3be..3dc0a612c3 100644 --- a/runtime/tests/CMakeLists.txt +++ b/runtime/tests/CMakeLists.txt @@ -78,6 +78,8 @@ if(ENABLE_OQD) target_link_libraries(runner_tests_oqd PRIVATE Catch2::Catch2 catalyst_qir_runtime + rt_OQD_capi + PRIVATE nlohmann_json::nlohmann_json ) target_sources(runner_tests_oqd PRIVATE diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index 0f6d6dcafd..f35382541e 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -12,9 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "OQDDevice.cpp" +#include +#include #include +#include + +#include "RuntimeCAPI.h" +#include "TestUtils.hpp" + +#include "OQDDevice.cpp" +#include "OQDRuntimeCAPI.h" + +using json = nlohmann::json; using namespace Catalyst::Runtime::Device; @@ -29,3 +39,829 @@ TEST_CASE("Test the OQDDevice constructor", "[oqd]") REQUIRE_THROWS_WITH(device.Expval(0), Catch::Contains("Unsupported functionality")); REQUIRE_THROWS_WITH(device.Var(0), Catch::Contains("Unsupported functionality")); } + +TEST_CASE("Test OpenAPL Program generation", "[OQD]") +{ + json expected = json::parse(R"( +{ + "class_": "AtomicCircuit", + "system": { + "class_": "System", + "ions": [ + { + "class_": "Ion", + "mass": 171.0, + "charge": 1.0, + "levels": [ + { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + } + ], + "transitions": [ + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + } + ], + "position": [ + 0.0, + 0.0, + 0.0 + ] + }, + { + "class_": "Ion", + "mass": 171.0, + "charge": 1.0, + "levels": [ + { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + } + ], + "transitions": [ + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + } + ], + "position": [ + 0.0, + 0.0, + 0.0 + ] + } + ] + }, + "protocol": { + "class_": "SequentialProtocol", + "sequence": [ + { + "class_": "ParallelProtocol", + "sequence": [ + { + "class_": "Pulse", + "beam": { + "class_": "Beam", + "transition": { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + "rabi": { + "class_": "MathNum", + "value": 31.41592653589793 + }, + "detuning": { + "class_": "MathNum", + "value": 157.07963267948966 + }, + "phase": { + "class_": "MathNum", + "value": 0 + }, + "polarization": [ + 1.0, + 0.0, + 0.0 + ], + "wavevector": [ + 0.0, + 1.0, + 0.0 + ], + "target": 0 + }, + "duration": 2.0 + }, + { + "class_": "Pulse", + "beam": { + "class_": "Beam", + "transition": { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + "rabi": { + "class_": "MathNum", + "value": 31.41592653589793 + }, + "detuning": { + "class_": "MathNum", + "value": 157.07963267948966 + }, + "phase": { + "class_": "MathNum", + "value": 3.14 + }, + "polarization": [ + 1.0, + 0.0, + 0.0 + ], + "wavevector": [ + 0.0, + 1.0, + 0.0 + ], + "target": 0 + }, + "duration": 2.0 + } + ] + }, + { + "class_": "ParallelProtocol", + "sequence": [ + { + "class_": "Pulse", + "beam": { + "class_": "Beam", + "transition": { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + }, + "rabi": { + "class_": "MathNum", + "value": 31.41592653589793 + }, + "detuning": { + "class_": "MathNum", + "value": 157.07963267948966 + }, + "phase": { + "class_": "MathNum", + "value": 0 + }, + "polarization": [ + 0.0, + 0.0, + 1.0 + ], + "wavevector": [ + 0.0, + 0.0, + 1.0 + ], + "target": 0 + }, + "duration": 2.0 + }, + { + "class_": "Pulse", + "beam": { + "class_": "Beam", + "transition": { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + }, + "rabi": { + "class_": "MathNum", + "value": 31.41592653589793 + }, + "detuning": { + "class_": "MathNum", + "value": 157.07963267948966 + }, + "phase": { + "class_": "MathNum", + "value": -3.14 + }, + "polarization": [ + 0.0, + 0.0, + 1.0 + ], + "wavevector": [ + 1.0, + 0.0, + 0.0 + ], + "target": 1 + }, + "duration": 2.0 + } + ] + } + ] + } +} +)"); + + std::string this_file = __FILE__; + std::string this_directory = this_file.substr(0, this_file.find("/Test_OQDDevice.cpp")); + const auto [rtd_lib, rtd_name, rtd_kwargs] = + std::array{this_directory+"/../../frontend/catalyst/third_party/oqd/src/build/librtd_oqd.so", "oqd", R"({'shots': 0, 'mcmc': False}ION: + { + "class_": "Ion", + "mass": 171.0, + "charge": 1.0, + "levels": [ + { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + } + ], + "transitions": [ + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l0", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 0.0 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l2", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0, + "energy": 628.3185307179587 + }, + "einsteinA": 1.0 + }, + { + "class_": "Transition", + "level1": { + "class_": "Level", + "label": "l1", + "principal": 6, + "spin": 0.5, + "orbital": 0.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0, + "energy": 62.83185307179586 + }, + "level2": { + "class_": "Level", + "label": "l3", + "principal": 5, + "spin": 0.5, + "orbital": 1.0, + "nuclear": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0, + "energy": 1256.6370614359173 + }, + "einsteinA": 1.0 + } + ], + "position": [ + 0.0, + 0.0, + 0.0 + ] + })"}; + + size_t num_qubits = 2; + + Beam beam1 = {0, 31.41592653589793, 157.07963267948966, {1, 0, 0}, {0, 1, 0}}; + Beam beam2 = {2, 31.41592653589793, 157.07963267948966, {1, 0, 0}, {0, 1, 0}}; + + Beam beam3 = {1, 31.41592653589793, 157.07963267948966, {0, 0, 1}, {0, 0, 1}}; + Beam beam4 = {3, 31.41592653589793, 157.07963267948966, {0, 0, 1}, {1, 0, 0}}; + + __catalyst__rt__initialize(nullptr); + __catalyst__rt__device_init((int8_t *)rtd_lib.c_str(), (int8_t *)rtd_name.c_str(), + (int8_t *)rtd_kwargs.c_str(), 1000); + + QirArray *qs = __catalyst__rt__qubit_allocate_array(num_qubits); + + QUBIT **target0 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 0); + QUBIT **target1 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 1); + + + Pulse *pulse1 = __catalyst__oqd__pulse(*target0, 2.0, 0.00, &beam1); + Pulse *pulse2 = __catalyst__oqd__pulse(*target0, 2.0, 3.14, &beam2); + Pulse *pulses12[] = {pulse1, pulse2}; + __catalyst__oqd__ParallelProtocol(pulses12, 2); + + Pulse *pulse3 = __catalyst__oqd__pulse(*target0, 2.0, 0.00, &beam3); + Pulse *pulse4 = __catalyst__oqd__pulse(*target1, 2.0, -3.14, &beam4); + Pulse *pulses34[] = {pulse3, pulse4}; + __catalyst__oqd__ParallelProtocol(pulses34, 2); + + __catalyst__rt__qubit_release_array(qs); + __catalyst__rt__device_release(); + __catalyst__rt__finalize(); + + json observed = json::parse(std::ifstream("__openapl__output.json")); + CHECK(expected == observed); + CHECK(1 == 0); + + std::filesystem::remove("__openapl__output.json"); +} From c1bc821b6d20241dfba42ee9e664162e2cee9dcd Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 12:09:38 -0500 Subject: [PATCH 04/61] update oqd device.so path in test --- runtime/tests/Test_OQDDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index f35382541e..b6e2b5468f 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -651,7 +651,7 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") std::string this_file = __FILE__; std::string this_directory = this_file.substr(0, this_file.find("/Test_OQDDevice.cpp")); const auto [rtd_lib, rtd_name, rtd_kwargs] = - std::array{this_directory+"/../../frontend/catalyst/third_party/oqd/src/build/librtd_oqd.so", "oqd", R"({'shots': 0, 'mcmc': False}ION: + std::array{this_directory+"/../build/lib/librtd_oqd_device.so", "oqd", R"({'shots': 0, 'mcmc': False}ION: { "class_": "Ion", "mass": 171.0, From ff539263163d13bba534c45d3c07f0803f964a45 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 12:27:53 -0500 Subject: [PATCH 05/61] format --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 14 ++++++-------- runtime/lib/backend/oqd/OQDDevice.cpp | 8 +++++--- runtime/lib/backend/oqd/OQDDevice.hpp | 2 +- runtime/tests/Test_OQDDevice.cpp | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 2e39977b63..e352b8dc1c 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -157,14 +157,12 @@ struct IonOpPattern : public OpConversionPattern { std::string level0_label = transitionAttr.getLevel_0().getValue().str(); std::string level1_label = transitionAttr.getLevel_1().getValue().str(); - assert(LevelLabel2Index.count(level0_label) == 1 - && LevelLabel2Index.count(level1_label) == 1 - && "A transition level's label must refer to an existing level in the ion!"); - - const json &level1 = - ion_json["levels"][LevelLabel2Index[level0_label]]; - const json &level2 = - ion_json["levels"][LevelLabel2Index[level1_label]]; + assert(LevelLabel2Index.count(level0_label) == 1 && + LevelLabel2Index.count(level1_label) == 1 && + "A transition level's label must refer to an existing level in the ion!"); + + const json &level1 = ion_json["levels"][LevelLabel2Index[level0_label]]; + const json &level2 = ion_json["levels"][LevelLabel2Index[level1_label]]; json this_transition = json{{"class_", "Transition"}, diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index 5a36d71a90..80356ef481 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -27,12 +27,14 @@ auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector // need to return a vector from 0 to num_qubits std::vector result(num_qubits); - std::generate_n(result.begin(), num_qubits, - []() { static size_t i=0; return i++; }); + std::generate_n(result.begin(), num_qubits, []() { + static size_t i = 0; + return i++; + }); return result; } -void OQDDevice::ReleaseAllQubits() { this->ion_specs=""; } +void OQDDevice::ReleaseAllQubits() { this->ion_specs = ""; } void OQDDevice::ReleaseQubit([[maybe_unused]] QubitIdType q) { diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index ef3ca4e003..14b54787e7 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -68,7 +68,7 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { // and ion_json is a JSON spec string for the ion std::string ion_token = "ION:"; size_t ion_token_pos = kwargs.find(ion_token); - ion_specs = kwargs.substr(ion_token_pos+ion_token.length()); + ion_specs = kwargs.substr(ion_token_pos + ion_token.length()); device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs.substr(0, ion_token_pos)); device_shots = device_kwargs.contains("shots") diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index b6e2b5468f..e2b10884f1 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -651,7 +651,8 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") std::string this_file = __FILE__; std::string this_directory = this_file.substr(0, this_file.find("/Test_OQDDevice.cpp")); const auto [rtd_lib, rtd_name, rtd_kwargs] = - std::array{this_directory+"/../build/lib/librtd_oqd_device.so", "oqd", R"({'shots': 0, 'mcmc': False}ION: + std::array{this_directory + "/../build/lib/librtd_oqd_device.so", "oqd", + R"({'shots': 0, 'mcmc': False}ION: { "class_": "Ion", "mass": 171.0, @@ -844,7 +845,6 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") QUBIT **target0 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 0); QUBIT **target1 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 1); - Pulse *pulse1 = __catalyst__oqd__pulse(*target0, 2.0, 0.00, &beam1); Pulse *pulse2 = __catalyst__oqd__pulse(*target0, 2.0, 3.14, &beam2); Pulse *pulses12[] = {pulse1, pulse2}; From 7de433909f491e6222ac1733891c85a95572bdc8 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 13:35:51 -0500 Subject: [PATCH 06/61] discover oqd device.so in execution context --- runtime/lib/capi/ExecutionContext.hpp | 4 ++++ runtime/tests/Test_OQDDevice.cpp | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/runtime/lib/capi/ExecutionContext.hpp b/runtime/lib/capi/ExecutionContext.hpp index 9abe8cb406..2e00e8ec72 100644 --- a/runtime/lib/capi/ExecutionContext.hpp +++ b/runtime/lib/capi/ExecutionContext.hpp @@ -202,6 +202,10 @@ class RTDevice { rtd_name = "OpenQasmDevice"; _complete_dylib_os_extension(rtd_lib, "openqasm"); } + else if (rtd_lib == "oqd.qubit") { + rtd_name = "oqd"; + _complete_dylib_os_extension(rtd_lib, "oqd_device"); + } } public: diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index e2b10884f1..9cf8a843b6 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -648,10 +648,8 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") } )"); - std::string this_file = __FILE__; - std::string this_directory = this_file.substr(0, this_file.find("/Test_OQDDevice.cpp")); const auto [rtd_lib, rtd_name, rtd_kwargs] = - std::array{this_directory + "/../build/lib/librtd_oqd_device.so", "oqd", + std::array{"oqd.qubit", "oqd", R"({'shots': 0, 'mcmc': False}ION: { "class_": "Ion", From f7f2c269d5468a499b62758161d8e7c3d0404872 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 14:31:23 -0500 Subject: [PATCH 07/61] remove check 1==0 fake test --- runtime/tests/Test_OQDDevice.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index 9cf8a843b6..038de9314f 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -859,7 +859,6 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") json observed = json::parse(std::ifstream("__openapl__output.json")); CHECK(expected == observed); - CHECK(1 == 0); std::filesystem::remove("__openapl__output.json"); } From b0b4027e1d22ae5c503228e1aa4d88d5346bc966 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 14:41:41 -0500 Subject: [PATCH 08/61] set device lib to "oqd.qubit" during loweing --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 2 ++ mlir/test/Ion/IonOpLowering.mlir | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index e352b8dc1c..3b1984238a 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -173,6 +173,8 @@ struct IonOpPattern : public OpConversionPattern { } deviceInitOp.setKwargs(deviceKwargs.str() + "ION:" + std::string(ion_json.dump())); + deviceInitOp.setLib("oqd.qubit"); + rewriter.eraseOp(op); return success(); } diff --git a/mlir/test/Ion/IonOpLowering.mlir b/mlir/test/Ion/IonOpLowering.mlir index 5a1b34a087..b6963a1516 100644 --- a/mlir/test/Ion/IonOpLowering.mlir +++ b/mlir/test/Ion/IonOpLowering.mlir @@ -22,7 +22,7 @@ func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {dif quantum.device shots(%c0_i64) ["blah.so", "OQD", "{'shots': 0, 'mcmc': False}"] // CHECK: quantum.device -// CHECK-SAME: ["blah.so", "OQD", "{'shots': 0, 'mcmc': False}ION: +// CHECK-SAME: ["oqd.qubit", "OQD", "{'shots': 0, 'mcmc': False}ION: // COM: nlohmann-json library dumps double quotation literals in json strings as \22 // COM: nlohmann-json library dumps JSON specs in alphabetical order // CHECK-SAME: { From 93a8ac534b01ead9e3ab121aeec73f3962f59c69 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 15:27:23 -0500 Subject: [PATCH 09/61] update stub signature in mlir to agree with runtime --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 3b1984238a..0797690b36 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -244,13 +244,16 @@ struct ParallelProtocolOpPattern : public OpConversionPatternconvertType(IonType::get(ctx)); Type protocolFuncType = - LLVM::LLVMFunctionType::get(protocolResultType, {ptrType, pulseArraySize.getType()}); + LLVM::LLVMFunctionType::get(LLVM::LLVMVoidType::get(ctx), {ptrType, pulseArraySize.getType()}); std::string protocolFuncName = "__catalyst__oqd__ParallelProtocol"; LLVM::LLVMFuncOp protocolFnDecl = ensureFunctionDeclaration(rewriter, op, protocolFuncName, protocolFuncType); - rewriter.replaceOpWithNewOp(op, protocolFnDecl, operands); + rewriter.create(loc, protocolFnDecl, operands); + + SmallVector values; + values.insert(values.end(), adaptor.getInQubits().begin(), adaptor.getInQubits().end()); + rewriter.replaceOp(op, values); return success(); } From ef5c37c04026760551a493d296e6cbb9aea16fed Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 15:36:42 -0500 Subject: [PATCH 10/61] update mlir test --- mlir/test/Ion/ParallelProtocolOpLowering.mlir | 62 +++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/mlir/test/Ion/ParallelProtocolOpLowering.mlir b/mlir/test/Ion/ParallelProtocolOpLowering.mlir index 64ecf699e0..46d470899c 100644 --- a/mlir/test/Ion/ParallelProtocolOpLowering.mlir +++ b/mlir/test/Ion/ParallelProtocolOpLowering.mlir @@ -15,16 +15,21 @@ // RUN: quantum-opt %s --convert-ion-to-llvm --split-input-file -verify-diagnostics | FileCheck %s // CHECK: llvm.func @__catalyst__oqd__pulse(!llvm.ptr, f64, f64, !llvm.ptr) -> !llvm.ptr -// CHECK: llvm.func @__catalyst__oqd__ParallelProtocol(!llvm.ptr, i64) -> !llvm.ptr +// CHECK: llvm.func @__catalyst__oqd__ParallelProtocol(!llvm.ptr, i64) // CHECK-LABEL: parallel_protocol_op func.func public @parallel_protocol_op(%arg0: f64) -> !quantum.bit { + // Get wire number + // CHECK: {{.+}} = quantum.alloc( 1) : !quantum.reg + // CHECK: {{.+}} = quantum.extract {{.+}}[ 0] : !quantum.reg -> !quantum.bit + // CHECK: [[wire:%.+]] = builtin.unrealized_conversion_cast {{.+}} : !quantum.bit to !llvm.ptr + // Pulse 1 - // CHECK: %[[pulse_1:.*]] = llvm.call @__catalyst__oqd__pulse + // CHECK: %[[pulse_1:.*]] = llvm.call @__catalyst__oqd__pulse([[wire]] // Pulse 2 - // CHECK: %[[pulse_2:.*]] = llvm.call @__catalyst__oqd__pulse + // CHECK: %[[pulse_2:.*]] = llvm.call @__catalyst__oqd__pulse([[wire]] // Pulse array // CHECK: %[[pulse_array:.*]] = llvm.mlir.undef : !llvm.array<2 x ptr> @@ -38,8 +43,29 @@ func.func public @parallel_protocol_op(%arg0: f64) -> !quantum.bit { // Parallel Protocol Stub // CHECK: %[[pulse_array_size:.*]] = llvm.mlir.constant(2 : i64) : i64 - // CHECK: %[[pp:.*]] = llvm.call @__catalyst__oqd__ParallelProtocol(%[[pulse_array_ptr:.*]], %[[pulse_array_size:.*]]) : (!llvm.ptr, i64) -> !llvm.ptr + // CHECK: llvm.call @__catalyst__oqd__ParallelProtocol(%[[pulse_array_ptr:.*]], %[[pulse_array_size:.*]]) : (!llvm.ptr, i64) + + + // Second gate + // Pulse 1 + // CHECK: %[[pulse_1_2:.*]] = llvm.call @__catalyst__oqd__pulse([[wire]] + + // Pulse 2 + // CHECK: %[[pulse_2_2:.*]] = llvm.call @__catalyst__oqd__pulse([[wire]] + + // Pulse array + // CHECK: %[[pulse_array_2:.*]] = llvm.mlir.undef : !llvm.array<2 x ptr> + // CHECK: %[[pulse_array_insert_0_2:.*]] = llvm.insertvalue %[[pulse_1_ptr_2:.*]], %[[pulse_array_2:.*]][0] : !llvm.array<2 x ptr> + // CHECK: %[[pulse_array_insert_1_2:.*]] = llvm.insertvalue %[[pulse_2_ptr_2:.*]], %[[pulse_array_2:.*]][1] : !llvm.array<2 x ptr> + + // Store pulse array on stack + // CHECK: %[[c1_2:.*]] = llvm.mlir.constant(1 : i64) : i64 + // CHECK: %[[pulse_array_ptr_2:.*]] = llvm.alloca %[[c1_2:.*]] x !llvm.array<2 x ptr> : (i64) -> !llvm.ptr + // CHECK: llvm.store %[[pulse_array_insert_1_2:.*]], %[[pulse_array_ptr_2:.*]] : !llvm.array<2 x ptr>, !llvm.ptr + // Parallel Protocol Stub + // CHECK: %[[pulse_array_size_2:.*]] = llvm.mlir.constant(2 : i64) : i64 + // CHECK: llvm.call @__catalyst__oqd__ParallelProtocol(%[[pulse_array_ptr_2:.*]], %[[pulse_array_size_2:.*]]) : (!llvm.ptr, i64) %qreg = quantum.alloc( 1) : !quantum.reg %q0 = quantum.extract %qreg[ 0] : !quantum.reg -> !quantum.bit @@ -70,5 +96,31 @@ func.func public @parallel_protocol_op(%arg0: f64) -> !quantum.bit { ion.yield %arg1: !quantum.bit } - return %pp: !quantum.bit + %pp1= ion.parallelprotocol(%pp) : !quantum.bit{ + ^bb0(%arg1: !quantum.bit): + %p1 = ion.pulse(%arg0: f64) %arg1 { + beam=#ion.beam< + transition_index=1, + rabi=10.10, + detuning=11.11, + polarization=[0, 1], + wavevector=[0, 1] + >, + phase=0.0 + } : !ion.pulse + + %p2 = ion.pulse(%arg0: f64) %arg1 { + beam=#ion.beam< + transition_index=0, + rabi=10.10, + detuning=11.11, + polarization=[0, 1], + wavevector=[0, 1] + >, + phase=0.0 + } : !ion.pulse + ion.yield %arg1: !quantum.bit + } + + return %pp1: !quantum.bit } From a468a90d3da3ec501269943eae4be542331210ea Mon Sep 17 00:00:00 2001 From: paul0403 Date: Wed, 12 Feb 2025 15:38:44 -0500 Subject: [PATCH 11/61] format --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 0797690b36..97981645bd 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -244,8 +244,8 @@ struct ParallelProtocolOpPattern : public OpConversionPattern Date: Wed, 12 Feb 2025 15:43:51 -0500 Subject: [PATCH 12/61] changelog --- doc/releases/changelog-dev.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 2856c3d709..93870f00c0 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -83,9 +83,14 @@ - Add a new pass `convert-ion-to-llvm` which lowers the Ion dialect to llvm dialect. This pass introduces oqd device specific stubs that will be implemented in oqd runtime including: - `@__catalyst_ion`, `@ __catalyst_pulse_op`, `@ __catalyst_parallel_protocol`. + `@__catalyst__oqd__ion`, `@ __catalyst__oqd__pulse`, `@ __catalyst__oqd__ParallelProtocol`. [(#1466)](https://github.com/PennyLaneAI/catalyst/pull/1466) + - The OQD device can now generate OpenAPL JSON specs during runtime. The oqd stubs + `@__catalyst__oqd__ion`, `@ __catalyst__oqd__pulse`, and `@ __catalyst__oqd__ParallelProtocol`, which + are called in the llvm dialect after the aforementioned lowering ([(#1466)](https://github.com/PennyLaneAI/catalyst/pull/1466)), are defined to produce JSON specs that OpenAPL expects. + [(#1516)](https://github.com/PennyLaneAI/catalyst/pull/1516) + - The OQD device is moved from `frontend/catalyst/third_party/oqd` to `runtime/lib/backend/oqd`. An overall switch, `ENABLE_OQD`, is added to control the OQD build system from a single entry point. The switch is `OFF` by default, and OQD can be built from source via `make all ENABLE_OQD=ON`, or `make runtime ENABLE_OQD=ON`. [(#1508)](https://github.com/PennyLaneAI/catalyst/pull/1508) From ea99d30b44359d8ab762496af1c2fe1b7f4f78cb Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 13 Feb 2025 10:04:02 -0500 Subject: [PATCH 13/61] update fetchcontent to use gittag instead of url --- mlir/lib/Ion/Transforms/CMakeLists.txt | 6 +++++- runtime/lib/OQDcapi/CMakeLists.txt | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mlir/lib/Ion/Transforms/CMakeLists.txt b/mlir/lib/Ion/Transforms/CMakeLists.txt index dea7ce5daa..1b79b56527 100644 --- a/mlir/lib/Ion/Transforms/CMakeLists.txt +++ b/mlir/lib/Ion/Transforms/CMakeLists.txt @@ -35,7 +35,11 @@ FetchContent_Declare( FetchContent_MakeAvailable(tomlplusplus) # Fetch json utilities -FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_Declare( + json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) FetchContent_MakeAvailable(json) target_link_libraries(ion-transforms PRIVATE nlohmann_json::nlohmann_json diff --git a/runtime/lib/OQDcapi/CMakeLists.txt b/runtime/lib/OQDcapi/CMakeLists.txt index 64c3c3deae..5142b197cd 100644 --- a/runtime/lib/OQDcapi/CMakeLists.txt +++ b/runtime/lib/OQDcapi/CMakeLists.txt @@ -6,7 +6,11 @@ add_library(catalyst_oqd_obj OBJECT OQDRuntimeCAPI.cpp) # Fetch json utilities include(FetchContent) -FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) +FetchContent_Declare( + json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) FetchContent_MakeAvailable(json) # link to rt_backend and json utils From 349c6a4531ef9676a2942e673868782d5d6e2c5f Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 13 Feb 2025 10:31:53 -0500 Subject: [PATCH 14/61] use url hash --- mlir/lib/Ion/Transforms/CMakeLists.txt | 6 +++--- runtime/lib/OQDcapi/CMakeLists.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mlir/lib/Ion/Transforms/CMakeLists.txt b/mlir/lib/Ion/Transforms/CMakeLists.txt index 1b79b56527..07ad842b40 100644 --- a/mlir/lib/Ion/Transforms/CMakeLists.txt +++ b/mlir/lib/Ion/Transforms/CMakeLists.txt @@ -36,9 +36,9 @@ FetchContent_MakeAvailable(tomlplusplus) # Fetch json utilities FetchContent_Declare( - json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.3 + json + URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz + URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d ) FetchContent_MakeAvailable(json) target_link_libraries(ion-transforms diff --git a/runtime/lib/OQDcapi/CMakeLists.txt b/runtime/lib/OQDcapi/CMakeLists.txt index 5142b197cd..4f168d4967 100644 --- a/runtime/lib/OQDcapi/CMakeLists.txt +++ b/runtime/lib/OQDcapi/CMakeLists.txt @@ -7,9 +7,9 @@ add_library(catalyst_oqd_obj OBJECT OQDRuntimeCAPI.cpp) # Fetch json utilities include(FetchContent) FetchContent_Declare( - json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.3 + json + URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz + URL_HASH SHA256=d6c65aca6b1ed68e7a182f4757257b107ae403032760ed6ef121c9d55e81757d ) FetchContent_MakeAvailable(json) From e1aea8e2dcbbe5a4f0e380d023e7f3cb814124ec Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 13 Feb 2025 11:48:36 -0500 Subject: [PATCH 15/61] add unit allocate/release tests (codecov); update to use qubit manager instead of manual --- runtime/lib/backend/oqd/OQDDevice.cpp | 15 +++++++++------ runtime/lib/backend/oqd/OQDDevice.hpp | 2 ++ runtime/tests/Test_OQDDevice.cpp | 22 +++++++++++++++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index 80356ef481..3cd6be65cc 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -19,6 +19,8 @@ namespace Catalyst::Runtime::Device { +auto OQDDevice::AllocateQubit() -> QubitIdType { RT_FAIL("Unsupported functionality"); } + auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector { for (size_t i = 0; i < num_qubits; i++) { @@ -27,14 +29,16 @@ auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector // need to return a vector from 0 to num_qubits std::vector result(num_qubits); - std::generate_n(result.begin(), num_qubits, []() { - static size_t i = 0; - return i++; - }); + std::generate_n(result.begin(), num_qubits, + [&]() { return this->qubit_manager.Allocate(num_qubits); }); return result; } -void OQDDevice::ReleaseAllQubits() { this->ion_specs = ""; } +void OQDDevice::ReleaseAllQubits() +{ + this->ion_specs = ""; + this->qubit_manager.ReleaseAll(); +} void OQDDevice::ReleaseQubit([[maybe_unused]] QubitIdType q) { @@ -78,7 +82,6 @@ void OQDDevice::PartialCounts(DataView &eigvals, DataView RT_FAIL("Unsupported functionality"); } -auto OQDDevice::AllocateQubit() -> QubitIdType { RT_FAIL("Unsupported functionality"); } void OQDDevice::PrintState() { RT_FAIL("Unsupported functionality"); } void OQDDevice::Counts(DataView &eigvals, DataView &counts, size_t shots) diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index 14b54787e7..7226da9de4 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -82,5 +82,7 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { QUANTUM_DEVICE_RT_DECLARATIONS; QUANTUM_DEVICE_QIS_DECLARATIONS; + + const std::string &getIonSpecs() { return ion_specs; } }; } // namespace Catalyst::Runtime::Device diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index 038de9314f..0c538e2e6b 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -40,7 +40,24 @@ TEST_CASE("Test the OQDDevice constructor", "[oqd]") REQUIRE_THROWS_WITH(device.Var(0), Catch::Contains("Unsupported functionality")); } -TEST_CASE("Test OpenAPL Program generation", "[OQD]") +TEST_CASE("Test the OQDDevice qubit allocation and release", "[oqd]") +{ + auto device = OQDDevice(R"({shots : 100}ION:{"name":"Yb171"})"); + + CHECK(device.getIonSpecs() == "{\"name\":\"Yb171\"}"); + + std::vector allocaedQubits = device.AllocateQubits(3); + CHECK(allocaedQubits[0] == 0); + CHECK(allocaedQubits[1] == 1); + CHECK(allocaedQubits[2] == 2); + + device.ReleaseAllQubits(); + CHECK(device.getIonSpecs() == ""); + + std::filesystem::remove("__openapl__output.json"); +} + +TEST_CASE("Test OpenAPL Program generation", "[oqd]") { json expected = json::parse(R"( { @@ -843,6 +860,9 @@ TEST_CASE("Test OpenAPL Program generation", "[OQD]") QUBIT **target0 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 0); QUBIT **target1 = (QUBIT **)__catalyst__rt__array_get_element_ptr_1d(qs, 1); + CHECK(reinterpret_cast(*target0) == 0); + CHECK(reinterpret_cast(*target1) == 1); + Pulse *pulse1 = __catalyst__oqd__pulse(*target0, 2.0, 0.00, &beam1); Pulse *pulse2 = __catalyst__oqd__pulse(*target0, 2.0, 3.14, &beam2); Pulse *pulses12[] = {pulse1, pulse2}; From 554446c233bbe5976c375944eb9457c4588aa911 Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 13 Feb 2025 12:09:06 -0500 Subject: [PATCH 16/61] add transition label ("l0->l1") --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 3 ++- mlir/test/Ion/IonOpLowering.mlir | 3 +++ runtime/tests/Test_OQDDevice.cpp | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 97981645bd..2e61a460d5 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -168,7 +168,8 @@ struct IonOpPattern : public OpConversionPattern { json{{"class_", "Transition"}, {"einsteinA", transitionAttr.getEinsteinA().getValue().convertToDouble()}, {"level1", level1}, - {"level2", level2}}; + {"level2", level2}, + {"label", level0_label + "->" + level1_label}}; ion_json["transitions"].push_back(this_transition); } deviceInitOp.setKwargs(deviceKwargs.str() + "ION:" + std::string(ion_json.dump())); diff --git a/mlir/test/Ion/IonOpLowering.mlir b/mlir/test/Ion/IonOpLowering.mlir index b6963a1516..5840eba0f8 100644 --- a/mlir/test/Ion/IonOpLowering.mlir +++ b/mlir/test/Ion/IonOpLowering.mlir @@ -84,6 +84,7 @@ func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {dif // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Transition\22, // CHECK-SAME: \22einsteinA\22:2.2, +// CHECK-SAME: \22label\22:\22l0->l2\22, // CHECK-SAME: \22level1\22: // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Level\22, @@ -114,6 +115,7 @@ func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {dif // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Transition\22, // CHECK-SAME: \22einsteinA\22:1.1, +// CHECK-SAME: \22label\22:\22l1->l2\22, // CHECK-SAME: \22level1\22: // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Level\22, @@ -144,6 +146,7 @@ func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {dif // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Transition\22, // CHECK-SAME: \22einsteinA\22:3.3, +// CHECK-SAME: \22label\22:\22l0->l3\22, // CHECK-SAME: \22level1\22: // CHECK-SAME: { // CHECK-SAME: \22class_\22:\22Level\22, diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index 0c538e2e6b..f59336bb31 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -122,6 +122,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "transitions": [ { "class_": "Transition", + "label": "l0->l2", "level1": { "class_": "Level", "label": "l0", @@ -150,6 +151,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l0->l3", "level1": { "class_": "Level", "label": "l0", @@ -178,6 +180,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l2", "level1": { "class_": "Level", "label": "l1", @@ -206,6 +209,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l3", "level1": { "class_": "Level", "label": "l1", @@ -296,6 +300,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "transitions": [ { "class_": "Transition", + "label": "l0->l2", "level1": { "class_": "Level", "label": "l0", @@ -324,6 +329,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l0->l3", "level1": { "class_": "Level", "label": "l0", @@ -352,6 +358,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l2", "level1": { "class_": "Level", "label": "l1", @@ -380,6 +387,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l3", "level1": { "class_": "Level", "label": "l1", @@ -427,6 +435,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "class_": "Beam", "transition": { "class_": "Transition", + "label": "l0->l2", "level1": { "class_": "Level", "label": "l0", @@ -485,6 +494,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "class_": "Beam", "transition": { "class_": "Transition", + "label": "l1->l2", "level1": { "class_": "Level", "label": "l1", @@ -548,6 +558,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "class_": "Beam", "transition": { "class_": "Transition", + "label": "l0->l3", "level1": { "class_": "Level", "label": "l0", @@ -606,6 +617,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "class_": "Beam", "transition": { "class_": "Transition", + "label": "l1->l3", "level1": { "class_": "Level", "label": "l1", @@ -725,6 +737,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "transitions": [ { "class_": "Transition", + "label": "l0->l2", "level1": { "class_": "Level", "label": "l0", @@ -753,6 +766,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l0->l3", "level1": { "class_": "Level", "label": "l0", @@ -781,6 +795,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l2", "level1": { "class_": "Level", "label": "l1", @@ -809,6 +824,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }, { "class_": "Transition", + "label": "l1->l3", "level1": { "class_": "Level", "label": "l1", From 8d48bf86307ca587dc4dfe0e24ced4051887f3fa Mon Sep 17 00:00:00 2001 From: paul0403 Date: Thu, 13 Feb 2025 13:36:25 -0500 Subject: [PATCH 17/61] link to oqd capi from python --- frontend/catalyst/compiler.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/catalyst/compiler.py b/frontend/catalyst/compiler.py index 8be2572507..9574870d27 100644 --- a/frontend/catalyst/compiler.py +++ b/frontend/catalyst/compiler.py @@ -170,6 +170,11 @@ def get_default_flags(options): "-lcustom_calls", "-lmlir_async_runtime", ] + + # If OQD runtime capi is built, link to it as well + if os.path.isfile(os.path.join(rt_lib_path, "librtd_oqd_device" + file_extension)): + default_flags.append("-lrt_OQD_capi") + return default_flags @staticmethod From 0b39f13d3a976e53a382ee785354cda783cc3806 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 12 Feb 2025 11:32:50 -0500 Subject: [PATCH 18/61] make toml file parameter types cinsistent wih oqd AtomicCircuit types --- .../oqd_gate_decomposition_parameters.toml | 22 +++++----- mlir/test/Ion/oqd_qubit_parameters.toml | 43 +++++++++++-------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml index c57f9096c7..34f1891335 100644 --- a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml +++ b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml @@ -37,39 +37,39 @@ oqd_config_schema = "v0.1" [[beams1]] rabi = 1.1 detuning = 2.2 -polarization = [0,1] -wavevector = [-2,3] +polarization = [0,1,2] +wavevector = [-2,3,4] [[beams1]] rabi = 4.4 detuning = 5.5 -polarization = [6,7] -wavevector = [8,9] +polarization = [6,7,8] +wavevector = [8,9,10] [[beams1]] rabi = 10.10 detuning = 11.11 -polarization = [12,13] -wavevector = [14,15] +polarization = [12,13,14] +wavevector = [14,15,16] [[beams2]] rabi = 1.23 detuning = 4.56 -polarization = [7,8] -wavevector = [9,10] +polarization = [7,8,9] +wavevector = [9,10,11] [[beams2]] rabi = 4.56 detuning = 7.89 polarization = [1,2] -wavevector = [-3,4] +wavevector = [-3,4,5] [[beams2]] rabi = 99.99 detuning = 100.100 -polarization = [37,42] -wavevector = [-42,-37] +polarization = [37,42,43] +wavevector = [-42,-37,-43] # Phonons diff --git a/mlir/test/Ion/oqd_qubit_parameters.toml b/mlir/test/Ion/oqd_qubit_parameters.toml index 75b0f3ff02..45767e1dd5 100644 --- a/mlir/test/Ion/oqd_qubit_parameters.toml +++ b/mlir/test/Ion/oqd_qubit_parameters.toml @@ -28,45 +28,52 @@ position = [1.0, 2.0, -1.0] levels.downstate.label = "downstate" levels.downstate.principal = 6 -levels.downstate.spin = 0.4 -levels.downstate.orbital = 0.5 -levels.downstate.nuclear = 0.6 -levels.downstate.spin_orbital = 0.8 -levels.downstate.spin_orbital_nuclear = 0.9 -levels.downstate.spin_orbital_nuclear_magnetization = 1.0 +levels.downstate.spin = 0.5 +levels.downstate.orbital = 1.0 +levels.downstate.nuclear = 1.5 +levels.downstate.spin_orbital = 2.0 +levels.downstate.spin_orbital_nuclear = 2.5 +levels.downstate.spin_orbital_nuclear_magnetization = -3.0 levels.downstate.energy = 0.0 levels.upstate.label = "upstate" levels.upstate.principal = 6 -levels.upstate.spin = 1.4 -levels.upstate.orbital = 1.5 -levels.upstate.nuclear = 1.6 -levels.upstate.spin_orbital = 1.8 -levels.upstate.spin_orbital_nuclear = 1.9 -levels.upstate.spin_orbital_nuclear_magnetization = 2.0 +levels.downstate.spin = 1.5 +levels.downstate.orbital = 2.0 +levels.downstate.nuclear = 2.5 +levels.downstate.spin_orbital = 3.0 +levels.downstate.spin_orbital_nuclear = 3.5 +levels.downstate.spin_orbital_nuclear_magnetization = -4.0 levels.upstate.energy = 12.643e9 levels.estate.label = "estate" levels.estate.principal = 5 -levels.estate.spin = 2.4 -levels.estate.orbital = 2.5 -levels.estate.nuclear = 2.6 -levels.estate.spin_orbital = 2.8 -levels.estate.spin_orbital_nuclear = 2.9 -levels.estate.spin_orbital_nuclear_magnetization = 3.0 +levels.downstate.spin = 2.5 +levels.downstate.orbital = 3.0 +levels.downstate.nuclear = 3.5 +levels.downstate.spin_orbital = 4.0 +levels.downstate.spin_orbital_nuclear = 4.5 +levels.downstate.spin_orbital_nuclear_magnetization = -5.0 levels.estate.energy = 811.52e12 [ions.Yb171.transitions.downstate_upstate] +label = "downstate->upstate" level1 = "downstate" level2 = "upstate" einstein_a = 1.1 +multipole = "M1" [ions.Yb171.transitions.downstate_estate] +label = "downstate->estate" level1 = "downstate" level2 = "estate" einstein_a = 2.2 +multipole = "E2" [ions.Yb171.transitions.estate_upstate] +label = "estate->upstate" level1 = "estate" level2 = "upstate" einstein_a = 3.3 +multipole = "E1" + From 4d53478ac0d2f3b4036fa7265180b4325437fc82 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 12 Feb 2025 13:32:05 -0500 Subject: [PATCH 19/61] Fixed typo --- mlir/test/Ion/oqd_qubit_parameters.toml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mlir/test/Ion/oqd_qubit_parameters.toml b/mlir/test/Ion/oqd_qubit_parameters.toml index 45767e1dd5..6ae157718c 100644 --- a/mlir/test/Ion/oqd_qubit_parameters.toml +++ b/mlir/test/Ion/oqd_qubit_parameters.toml @@ -38,22 +38,22 @@ levels.downstate.energy = 0.0 levels.upstate.label = "upstate" levels.upstate.principal = 6 -levels.downstate.spin = 1.5 -levels.downstate.orbital = 2.0 -levels.downstate.nuclear = 2.5 -levels.downstate.spin_orbital = 3.0 -levels.downstate.spin_orbital_nuclear = 3.5 -levels.downstate.spin_orbital_nuclear_magnetization = -4.0 +levels.upstate.spin = 1.5 +levels.upstate.orbital = 2.0 +levels.upstate.nuclear = 2.5 +levels.upstate.spin_orbital = 3.0 +levels.upstate.spin_orbital_nuclear = 3.5 +levels.upstate.spin_orbital_nuclear_magnetization = -4.0 levels.upstate.energy = 12.643e9 levels.estate.label = "estate" levels.estate.principal = 5 -levels.downstate.spin = 2.5 -levels.downstate.orbital = 3.0 -levels.downstate.nuclear = 3.5 -levels.downstate.spin_orbital = 4.0 -levels.downstate.spin_orbital_nuclear = 4.5 -levels.downstate.spin_orbital_nuclear_magnetization = -5.0 +levels.estate.spin = 2.5 +levels.estate.orbital = 3.0 +levels.estate.nuclear = 3.5 +levels.estate.spin_orbital = 4.0 +levels.estate.spin_orbital_nuclear = 4.5 +levels.estate.spin_orbital_nuclear_magnetization = -5.0 levels.estate.energy = 811.52e12 [ions.Yb171.transitions.downstate_upstate] From 0500dbbf6836cf1413723e185b6d3b30f65bdb21 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 12 Feb 2025 16:59:07 -0500 Subject: [PATCH 20/61] Add multipole to Transitions in Ion dialect --- mlir/include/Ion/IR/IonOps.td | 8 +++++--- mlir/include/Ion/Transforms/oqd_database_managers.hpp | 3 ++- mlir/include/Ion/Transforms/oqd_database_types.hpp | 7 ++++--- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 2 ++ mlir/lib/Ion/Transforms/quantum_to_ion.cpp | 3 ++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/mlir/include/Ion/IR/IonOps.td b/mlir/include/Ion/IR/IonOps.td index 41b4464eca..5fe14159f3 100644 --- a/mlir/include/Ion/IR/IonOps.td +++ b/mlir/include/Ion/IR/IonOps.td @@ -86,14 +86,16 @@ def TransitionAttr : Ion_Attr<"Transition", "transition"> { let parameters = (ins "mlir::StringAttr":$level_0, "mlir::StringAttr":$level_1, - "mlir::FloatAttr":$einstein_a + "mlir::FloatAttr":$einstein_a, + "mlir::StringAttr":$multipole ); let builders = [ AttrBuilderWithInferredContext<(ins "mlir::StringAttr":$level_0, "mlir::StringAttr":$level_1, - "mlir::FloatAttr":$einstein_a), [{ - return $_get(einstein_a.getContext(), level_0, level_1, einstein_a); + "mlir::FloatAttr":$einstein_a, + "mlir::StringAttr":$multipole), [{ + return $_get(einstein_a.getContext(), level_0, level_1, einstein_a, multipole); }]> ]; diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index 4acab42234..d44e66e00b 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -160,13 +160,14 @@ class OQDDatabaseManager { double einstein_a = transition_entry["einstein_a"].as_floating_point()->get(); std::string level1 = transition_entry["level1"].as_string()->get(); std::string level2 = transition_entry["level2"].as_string()->get(); + std::string multipole = transition_entry["multipole"].as_string()->get(); std::set levelEncodings{"downstate", "upstate", "estate"}; assert((levelEncodings.count(level1) & levelEncodings.count(level2)) && "Only \"downstate\", \"upstate\" and \"estate\" are allowed in the atom's " "transition levels."); - return Transition(level1, level2, einstein_a); + return Transition(level1, level2, multipole, einstein_a); }; for (auto &ion_it : *(ionsToml.as_table())) { diff --git a/mlir/include/Ion/Transforms/oqd_database_types.hpp b/mlir/include/Ion/Transforms/oqd_database_types.hpp index 3418c121a5..f87566fc2c 100644 --- a/mlir/include/Ion/Transforms/oqd_database_types.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_types.hpp @@ -81,11 +81,12 @@ struct Level { struct Transition { // This class represents a transition between two atomic levels. // It contains the innate properties of the qubit. - std::string level_0, level_1; + std::string level_0, level_1, multipole; double einstein_a; - Transition(std::string _level_0, std::string _level_1, double _einstein_a) - : level_0(_level_0), level_1(_level_1), einstein_a(_einstein_a) + Transition(std::string _level_0, std::string _level_1, std::string _multipole, + double _einstein_a) + : level_0(_level_0), level_1(_level_1), multipole(_multipole), einstein_a(_einstein_a) { } }; diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 2e61a460d5..022b1d5e22 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -154,6 +154,7 @@ struct IonOpPattern : public OpConversionPattern { for (size_t i = 0; i < transitionsAttr.size(); i++) { auto transitionAttr = cast(transitionsAttr[i]); + std::string multipole = transitionAttr.getMultipole().getValue().str(); std::string level0_label = transitionAttr.getLevel_0().getValue().str(); std::string level1_label = transitionAttr.getLevel_1().getValue().str(); @@ -170,6 +171,7 @@ struct IonOpPattern : public OpConversionPattern { {"level1", level1}, {"level2", level2}, {"label", level0_label + "->" + level1_label}}; + {"multipole", multipole}}; ion_json["transitions"].push_back(this_transition); } deviceInitOp.setKwargs(deviceKwargs.str() + "ION:" + std::string(ion_json.dump())); diff --git a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp index 64aec2e159..7759b63e44 100644 --- a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp +++ b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp @@ -57,7 +57,8 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { { return TransitionAttr::get(ctx, builder.getStringAttr(transition.level_0), builder.getStringAttr(transition.level_1), - builder.getF64FloatAttr(transition.einstein_a)); + builder.getF64FloatAttr(transition.einstein_a), + builder.getStringAttr(transition.multipole)); } bool canScheduleOn(RegisteredOperationName opInfo) const override From 80456642d06aaa0a527e072fad508cad532f9a0a Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 12 Feb 2025 16:59:21 -0500 Subject: [PATCH 21/61] Fix typo --- mlir/test/Ion/oqd_gate_decomposition_parameters.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml index 34f1891335..2aeb726fbe 100644 --- a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml +++ b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml @@ -62,7 +62,7 @@ wavevector = [9,10,11] [[beams2]] rabi = 4.56 detuning = 7.89 -polarization = [1,2] +polarization = [1,2,3] wavevector = [-3,4,5] [[beams2]] From 070581049fcdb56cb203ab459060c2b4b493c305 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 12 Feb 2025 16:59:36 -0500 Subject: [PATCH 22/61] Fix tests --- mlir/test/Ion/Dialect.mlir | 6 +- mlir/test/Ion/IonOpLowering.mlir | 9 +- mlir/test/Ion/QuantumToIon.mlir | 165 ++++++++++++++++--------------- 3 files changed, 94 insertions(+), 86 deletions(-) diff --git a/mlir/test/Ion/Dialect.mlir b/mlir/test/Ion/Dialect.mlir index f033b50ea7..32dff0d19b 100644 --- a/mlir/test/Ion/Dialect.mlir +++ b/mlir/test/Ion/Dialect.mlir @@ -183,12 +183,14 @@ func.func @example_ion() -> !ion.ion { #ion.transition< level_0 = "downstate", level_1 = "upstate", - einstein_a=10.10 + einstein_a=10.10, + multipole="M1" >, #ion.transition< level_0 = "upstate", level_1 = "downstate", - einstein_a=10.10 + einstein_a=10.10, + multipole="E1" > ] }: !ion.ion diff --git a/mlir/test/Ion/IonOpLowering.mlir b/mlir/test/Ion/IonOpLowering.mlir index 5840eba0f8..a07b432e7a 100644 --- a/mlir/test/Ion/IonOpLowering.mlir +++ b/mlir/test/Ion/IonOpLowering.mlir @@ -234,17 +234,20 @@ func.func public @ion_op(%arg0: tensor, %arg1: tensor) attributes {dif #ion.transition< level_0 = "l0", level_1 = "l2", - einstein_a = 2.200000e+00 : f64 + einstein_a = 2.200000e+00 : f64, + multipole = "M1" >, #ion.transition< level_0 = "l1", level_1 = "l2", - einstein_a = 1.100000e+00 : f64 + einstein_a = 1.100000e+00 : f64, + multipole = "E1" >, #ion.transition< level_0 = "l0", level_1 = "l3", - einstein_a = 3.300000e+00 : f64 + einstein_a = 3.300000e+00 : f64, + multipole = "E2" > ] } : !ion.ion diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index 845906963e..572aad7f81 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -32,34 +32,34 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: #ion.level< // CHECK-SAME: label = "downstate", // CHECK-SAME: principal = 6 - // CHECK-SAME: spin = 4.000000e-01 - // CHECK-SAME: orbital = 5.000000e-01 - // CHECK-SAME: nuclear = 6.000000e-01 - // CHECK-SAME: spin_orbital = 8.000000e-01 - // CHECK-SAME: spin_orbital_nuclear = 9.000000e-01 - // CHECK-SAME: spin_orbital_nuclear_magnetization = 1.000000e+00 + // CHECK-SAME: spin = 5.000000e-01 + // CHECK-SAME: orbital = 1.000000e+00 + // CHECK-SAME: nuclear = 1.500000e+00 + // CHECK-SAME: spin_orbital = 2.000000e+00 + // CHECK-SAME: spin_orbital_nuclear = 2.500000e+00 + // CHECK-SAME: spin_orbital_nuclear_magnetization = -3.000000e+00 // CHECK-SAME: energy = 0.000000e+00 // CHECK-SAME: >, // CHECK-SAME: #ion.level< // CHECK-SAME: label = "upstate", // CHECK-SAME: principal = 6 - // CHECK-SAME: spin = 1.400000e+00 - // CHECK-SAME: orbital = 1.500000e+00 - // CHECK-SAME: nuclear = 1.600000e+00 - // CHECK-SAME: spin_orbital = 1.800000e+00 - // CHECK-SAME: spin_orbital_nuclear = 1.900000e+00 - // CHECK-SAME: spin_orbital_nuclear_magnetization = 2.000000e+00 + // CHECK-SAME: spin = 1.500000e+00 + // CHECK-SAME: orbital = 2.000000e+00 + // CHECK-SAME: nuclear = 2.500000e+00 + // CHECK-SAME: spin_orbital = 3.000000e+00 + // CHECK-SAME: spin_orbital_nuclear = 3.500000e+00 + // CHECK-SAME: spin_orbital_nuclear_magnetization = -4.000000e+00 // CHECK-SAME: energy = 1.264300e+10 // CHECK-SAME: >, // CHECK-SAME: #ion.level< // CHECK-SAME: label = "estate", // CHECK-SAME: principal = 5 - // CHECK-SAME: spin = 2.400000e+00 - // CHECK-SAME: orbital = 2.500000e+00 - // CHECK-SAME: nuclear = 2.600000e+00 - // CHECK-SAME: spin_orbital = 2.800000e+00 - // CHECK-SAME: spin_orbital_nuclear = 2.900000e+00 - // CHECK-SAME: spin_orbital_nuclear_magnetization = 3.000000e+00 + // CHECK-SAME: spin = 2.500000e+00 + // CHECK-SAME: orbital = 3.000000e+00 + // CHECK-SAME: nuclear = 3.500000e+00 + // CHECK-SAME: spin_orbital = 4.000000e+00 + // CHECK-SAME: spin_orbital_nuclear = 4.500000e+00 + // CHECK-SAME: spin_orbital_nuclear_magnetization = -5.000000e+00 // CHECK-SAME: energy = 8.115200e+14 // CHECK-SAME: > // CHECK-SAME: ], @@ -70,17 +70,20 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: #ion.transition< // CHECK-SAME: level_0 = "downstate", // CHECK-SAME: level_1 = "estate", - // CHECK-SAME: einstein_a = 2.200000e+00 + // CHECK-SAME: einstein_a = 2.200000e+00 : f64, + // CHECK-SAME: multipole = "E2" // CHECK-SAME: >, // CHECK-SAME: #ion.transition< // CHECK-SAME: level_0 = "downstate", // CHECK-SAME: level_1 = "upstate", - // CHECK-SAME: einstein_a = 1.100000e+00 + // CHECK-SAME: einstein_a = 1.100000e+00 : f64, + // CHECK-SAME: multipole = "M1" // CHECK-SAME: >, // CHECK-SAME: #ion.transition< // CHECK-SAME: level_0 = "estate", // CHECK-SAME: level_1 = "upstate", - // CHECK-SAME: einstein_a = 3.300000e+00 + // CHECK-SAME: einstein_a = 3.300000e+00 : f64, + // CHECK-SAME: multipole = "E1" // CHECK-SAME: > // CHECK-SAME: ] // CHECK-SAME: } : !ion.ion @@ -101,16 +104,16 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.yield %arg1 : !quantum.bit // CHECK-NEXT: } @@ -125,16 +128,16 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 3.1415926535{{[0-9]*}} : f64} // CHECK-NEXT: ion.yield %arg1 : !quantum.bit // CHECK-NEXT: } @@ -149,16 +152,16 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, - // CHECK-SAME: polarization = [0, 1], - // CHECK-SAME: wavevector = [-2, 3]>, + // CHECK-SAME: polarization = [0, 1, 2], + // CHECK-SAME: wavevector = [-2, 3, 4]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.yield %arg1 : !quantum.bit // CHECK-NEXT: } @@ -173,48 +176,48 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [9, 10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 5.660000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 3.4{{.*}} : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [9, 10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 8.960000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 0.1{{.*}} : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit // CHECK-NEXT: } @@ -250,48 +253,48 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [9, 10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 5.660000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 3.4599999999999995 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [9, 10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 8.960000e+00 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 0.15999999999999925 : f64, - // CHECK-SAME: polarization = [7, 8], - // CHECK-SAME: wavevector = [-9, -10]>, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit // CHECK-NEXT: } @@ -306,48 +309,48 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 7.8899999999999996 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [-3, 4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [-3, 4, 5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 8.990000e+00 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [3, -4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 6.7899999999999991 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [3, -4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 7.8899999999999996 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [-3, 4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [-3, 4, 5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 1.559000e+01 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [3, -4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 0.1899999999999995 : f64, - // CHECK-SAME: polarization = [1, 2], - // CHECK-SAME: wavevector = [3, -4]>, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit // CHECK-NEXT: } @@ -362,48 +365,48 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.001000e+02 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [-42, -37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [-42, -37, -43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p2:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.045000e+02 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [42, 37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p3:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 95.699999999999989 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [42, 37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p4:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.001000e+02 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [-42, -37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [-42, -37, -43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p5:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.078000e+02 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [42, 37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p6:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 1 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 92.399999999999991 : f64, - // CHECK-SAME: polarization = [37, 42], - // CHECK-SAME: wavevector = [42, 37]>, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit // CHECK-NEXT: } From 419da91b0562ffe30cdc4ab09d1204efd1b3480f Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:40:40 -0500 Subject: [PATCH 23/61] Add toml files as class variables to oqd device class --- frontend/catalyst/third_party/oqd/oqd_device.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/catalyst/third_party/oqd/oqd_device.py b/frontend/catalyst/third_party/oqd/oqd_device.py index 01c229374b..d2f06328a2 100644 --- a/frontend/catalyst/third_party/oqd/oqd_device.py +++ b/frontend/catalyst/third_party/oqd/oqd_device.py @@ -47,7 +47,16 @@ def get_c_interface(): return "oqd", lib_path - def __init__(self, wires, shots, backend="default", **kwargs): + def __init__(self, wires, shots=None, backend="default", **kwargs): + self.device_toml = kwargs.pop("device_toml", []) + self.qubit_toml = kwargs.pop("qubit_toml", []) + self.gate_toml = kwargs.pop("gate_toml", []) + if not self.device_toml: + raise ValueError("device-toml file must be provided.") + if not self.qubit_toml: + raise ValueError("qubit-toml file must be provided.") + if not self.gate_toml: + raise ValueError("gate-toml file must be provided.") self._backend = backend _check_backend(backend=backend) super().__init__(wires=wires, shots=shots, **kwargs) From edf662a35914b026283d132143ea1b3eb408fa38 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:41:52 -0500 Subject: [PATCH 24/61] Add Phonon attribute and ModeOp to ion dialect --- mlir/include/Ion/IR/IonOps.td | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/mlir/include/Ion/IR/IonOps.td b/mlir/include/Ion/IR/IonOps.td index 5fe14159f3..6e4ad8a1c8 100644 --- a/mlir/include/Ion/IR/IonOps.td +++ b/mlir/include/Ion/IR/IonOps.td @@ -117,6 +117,22 @@ def BeamAttr : Ion_Attr<"Beam", "beam"> { let assemblyFormat = "`<` struct(params) `>`"; } +def PhononAttr : Ion_Attr<"Phonon", "phonon"> { + let summary = "A class to represent a Phonon mode."; + + let parameters = (ins + "mlir::FloatAttr":$energy, + "mlir::DenseF64ArrayAttr": $eignevector + ); + + let assemblyFormat = "`<` struct(params) `>`"; +} + +def PhononArrayAttr : TypedArrayAttrBase { + let constBuilderCall = ?; +} + def LevelArrayAttr : TypedArrayAttrBase { let constBuilderCall = ?; @@ -153,6 +169,18 @@ def IonOp : Ion_Op<"ion"> { }]; } +def ModesOp : Ion_Op<"mode"> { + let summary = "A class to represent an Phonon modes of the system."; + + let arguments = (ins + PhononArrayAttr: $modes + ); + + let assemblyFormat = [{ + attr-dict + }]; +} + def PulseOp : Ion_Op<"pulse"> { let summary = "Represent a pulse (a laser beam and some time)."; From 147fab069ef2c198e95d82b9f7da798b6572958f Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:44:30 -0500 Subject: [PATCH 25/61] remove PhononMode --- .../Ion/Transforms/oqd_database_managers.hpp | 21 +++++------- .../Ion/Transforms/oqd_database_types.hpp | 13 ++------ .../oqd_gate_decomposition_parameters.toml | 33 +++++++++---------- 3 files changed, 25 insertions(+), 42 deletions(-) diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index d44e66e00b..f8a42b0a61 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -50,7 +50,7 @@ class OQDDatabaseManager { const std::vector &getBeams1Params() const { return beams1; } const std::vector &getBeams2Params() const { return beams2; } - const std::vector &getPhononParams() const { return phonons; } + const std::vector &getPhononParams() const { return phonons; } const std::map &getIonParams() const { return ions; } @@ -62,7 +62,7 @@ class OQDDatabaseManager { std::vector beams1; std::vector beams2; - std::vector phonons; + std::vector phonons; std::map ions; @@ -109,23 +109,18 @@ class OQDDatabaseManager { void loadPhononParams() { toml::node_view phononsToml = sourceTomlGateDecomposition["phonons"]; - size_t numPhononModes = phononsToml.as_array()->size(); + size_t numPhonons = phononsToml.as_array()->size(); auto parseSingleDirection = [](auto direction) { double energy = direction["energy"].as_floating_point()->get(); - std::vector eigenvector = - tomlArray2StdVector(*(direction["eigenvector"].as_array())); + std::vector eigenvector = + tomlArray2StdVector(*(direction["eigenvector"].as_array())); return Phonon(energy, eigenvector); }; - for (size_t i = 0; i < numPhononModes; i++) { - auto phononMode = phononsToml[i]; - - Phonon COM_x = parseSingleDirection(phononMode["COM_x"]); - Phonon COM_y = parseSingleDirection(phononMode["COM_y"]); - Phonon COM_z = parseSingleDirection(phononMode["COM_z"]); - - phonons.push_back(PhononMode(COM_x, COM_y, COM_z)); + for (size_t i = 0; i < numPhonons; i++) { + Phonon phonon = parseSingleDirection(phononsToml[i]); + phonons.push_back(phonon); } } diff --git a/mlir/include/Ion/Transforms/oqd_database_types.hpp b/mlir/include/Ion/Transforms/oqd_database_types.hpp index f87566fc2c..f590ee3182 100644 --- a/mlir/include/Ion/Transforms/oqd_database_types.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_types.hpp @@ -39,23 +39,14 @@ struct Beam { struct Phonon { // This struct contains the calibrated phonon parameters on one axis. double energy; - std::vector eigenvector; + std::vector eigenvector; - Phonon(double _energy, std::vector _eigenvector) + Phonon(double _energy, std::vector _eigenvector) : energy(_energy), eigenvector(_eigenvector) { } }; -struct PhononMode { - // This struct contains the calibrated phonon parameters for one ion. - Phonon COM_x; - Phonon COM_y; - Phonon COM_z; - - PhononMode(Phonon x, Phonon y, Phonon z) : COM_x(x), COM_y(y), COM_z(z) {} -}; - // // Innate atomic parameters // diff --git a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml index 2aeb726fbe..5d8c5ae2ea 100644 --- a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml +++ b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml @@ -79,42 +79,39 @@ wavevector = [-42,-37,-43] # ------- [[phonons]] -[phonons.COM_x] energy = 1.1 -eigenvector = [1, 0, 0] +eigenvector = [1.0, 0.0, 0.0] -[phonons.COM_y] +[[phonons]] energy = 2.2 -eigenvector = [0, 1, 0] +eigenvector = [0.0, 1.0, 0.0] -[phonons.COM_z] +[[phonons]] energy = 3.3 -eigenvector = [0, 0, 1] +eigenvector = [0.0, 0.0, 1.0] [[phonons]] -[phonons.COM_x] energy = 4.4 -eigenvector = [1, 0, 0] +eigenvector = [1.0, 0.0, 0.0] -[phonons.COM_y] +[[phonons]] energy = 5.5 -eigenvector = [0, 1, 0] +eigenvector = [0.0, 1.0, 0.0] -[phonons.COM_z] +[[phonons]] energy = 6.6 -eigenvector = [0, 0, 1] +eigenvector = [0.0, 0.0, 1.0] [[phonons]] -[phonons.COM_x] energy = 7.7 -eigenvector = [1, 0, 0] +eigenvector = [1.0, 0.0, 0.0] -[phonons.COM_y] +[[phonons]] energy = 8.8 -eigenvector = [0, 1, 0] +eigenvector = [0.0, 1.0, 0.0] -[phonons.COM_z] +[[phonons]] energy = 9.9 -eigenvector = [0, 0, 1] +eigenvector = [0.0, 0.0, 1.0] From 4551f91d2c7394e75f6ccac21955e3b549c620ef Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:45:20 -0500 Subject: [PATCH 26/61] Fix indexing phonons in database --- mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index 39151d956b..04e7ca7561 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -205,7 +205,7 @@ mlir::LogicalResult oneQubitGateToPulse(CustomOp op, mlir::PatternRewriter &rewr mlir::LogicalResult MSGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter, const std::vector &beams2, - const std::vector &phonons) + const std::vector &phonons) { auto qnode = op->getParentOfType(); MLIRContext *ctx = op.getContext(); @@ -223,7 +223,7 @@ mlir::LogicalResult MSGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter, auto qubitIndex1Value = qubitIndex1.value(); auto nQubits = allocOp.getNqubitsAttr(); if (nQubits.has_value()) { - if (static_cast(qubitIndex0Value) >= phonons.size()) { + if (static_cast(qubitIndex0Value) * 3 >= phonons.size()) { op.emitError() << "Missing phonon parameters for qubit " << qubitIndex0Value << " used as input to MS gate; there are only " << phonons.size() << " phonon parameters in the database." @@ -232,7 +232,7 @@ mlir::LogicalResult MSGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter, return failure(); } - if (static_cast(qubitIndex1Value) >= phonons.size()) { + if (static_cast(qubitIndex1Value) * 3 >= phonons.size()) { op.emitError() << "Missing phonon parameters for qubit " << qubitIndex1Value << " used as input to MS gate; there are only " << phonons.size() << " phonon parameters in the database." @@ -241,9 +241,8 @@ mlir::LogicalResult MSGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter, return failure(); } - // Assume that each ion has 3 phonons (x, y, z) - const Phonon &phonon0ComX = phonons[qubitIndex0Value].COM_x; - const Phonon &phonon1ComX = phonons[qubitIndex1Value].COM_x; + const Phonon &phonon0ComX = phonons[qubitIndex0Value * 3]; + const Phonon &phonon1ComX = phonons[qubitIndex1Value * 3]; auto twoQubitComboIndex = getTwoQubitCombinationIndex(nQubits.value(), qubitIndex0Value, qubitIndex1Value); @@ -438,7 +437,7 @@ struct QuantumToIonRewritePattern : public mlir::OpConversionPattern { std::vector beams1; std::vector beams2; - std::vector phonons; + std::vector phonons; QuantumToIonRewritePattern(mlir::MLIRContext *ctx, const OQDDatabaseManager &dataManager) : mlir::OpConversionPattern::OpConversionPattern(ctx) From 99cdc642336aef0222c7779274ac77fa8acd64e7 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:46:04 -0500 Subject: [PATCH 27/61] Add lowering rules for ion.modes --- .../lib/Ion/Transforms/ConversionPatterns.cpp | 36 +++ mlir/lib/Ion/Transforms/quantum_to_ion.cpp | 12 + mlir/test/Ion/QuantumToIon.mlir | 206 ++---------------- 3 files changed, 65 insertions(+), 189 deletions(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 022b1d5e22..89d7c0c850 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -183,6 +183,41 @@ struct IonOpPattern : public OpConversionPattern { } }; +struct ModesOpPattern : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + // Create the modes JSON and pass it into the device kwargs as a JSON string + LogicalResult matchAndRewrite(catalyst::ion::ModesOp op, catalyst::ion::ModesOpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override + { + func::FuncOp funcOp = op->getParentOfType(); + + DeviceInitOp deviceInitOp = *funcOp.getOps().begin(); + + auto modesAttr = op.getModes(); + for (size_t i = 0; i < modesAttr.size(); i++) { + StringRef deviceKwargs = deviceInitOp.getKwargs(); + auto phononAttr = cast(modesAttr[i]); + + json phonon_json = R"({ + "class_": "Phonon", + "energy": [], + "eigenvector" : [] + })"_json; + phonon_json["energy"] = phononAttr.getEnergy().getValue().convertToDouble(); + auto eigenvector = phononAttr.getEignevector(); + for (int j = 0; j < eigenvector.size(); j++) { + phonon_json["eigenvector"].push_back(eigenvector[j]); + } + deviceInitOp.setKwargs(deviceKwargs.str() + + "PHONON:" + std::string(phonon_json.dump())); + } + + rewriter.eraseOp(op); + return success(); + } +}; + struct ParallelProtocolOpPattern : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; @@ -307,6 +342,7 @@ namespace ion { void populateConversionPatterns(LLVMTypeConverter &typeConverter, RewritePatternSet &patterns) { patterns.add(typeConverter, patterns.getContext()); + patterns.add(typeConverter, patterns.getContext()); patterns.add(typeConverter, patterns.getContext()); patterns.add(typeConverter, patterns.getContext()); } diff --git a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp index 7759b63e44..74a344f9c7 100644 --- a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp +++ b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp @@ -61,6 +61,12 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { builder.getStringAttr(transition.multipole)); } + PhononAttr getPhononAttr(MLIRContext *ctx, IRRewriter &builder, Phonon phonon) + { + return PhononAttr::get(ctx, builder.getF64FloatAttr(phonon.energy), + builder.getDenseF64ArrayAttr(phonon.eigenvector)); + } + bool canScheduleOn(RegisteredOperationName opInfo) const override { return opInfo.hasInterface(); @@ -100,6 +106,12 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { op->getLoc(), IonType::get(ctx), builder.getStringAttr(ion.name), builder.getF64FloatAttr(ion.mass), builder.getF64FloatAttr(ion.charge), ion.position, builder.getArrayAttr(levels), builder.getArrayAttr(transitions)); + + SmallVector phonons; + for (const Phonon &phonon : dataManager.getPhononParams()) { + phonons.push_back(cast(getPhononAttr(ctx, builder, phonon))); + } + builder.create(op->getLoc(), builder.getArrayAttr(phonons)); } RewritePatternSet ionPatterns(&getContext()); diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index 572aad7f81..7ee2f6ff21 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -88,6 +88,23 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: ] // CHECK-SAME: } : !ion.ion + // CHECK: ion.mode { + // CHECK-SAME: modes = [ + // CHECK-SAME: #ion.phonon< + // CHECK-SAME: energy = 1.100000e+00 : f64, + // CHECK-SAME: eignevector = [1.000000e+00, 0.000000e+00, 0.000000e+00] + // CHECK-SAME: >, + // CHECK-SAME: #ion.phonon< + // CHECK-SAME: energy = 2.200000e+00 : f64, + // CHECK-SAME: eignevector = [0.000000e+00, 1.000000e+00, 0.000000e+00] + // CHECK-SAME: >, + // CHECK-SAME: #ion.phonon< + // CHECK-SAME: energy = 3.300000e+00 : f64, + // CHECK-SAME: eignevector = [0.000000e+00, 0.000000e+00, 1.000000e+00] + // CHECK-SAME: > + // CHECK-SAME: ] + // CHECK-SAME: } + %1 = quantum.alloc( 2) : !quantum.reg // CHECK: [[qubit0:%.+]] = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit @@ -224,192 +241,3 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} %7:2 = quantum.custom "MS"(%arg0) %6, %3 : !quantum.bit, !quantum.bit return %7#0: !quantum.bit } - - -// ----- - - -// CHECK-LABEL: example_ion_three_qubit -func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !quantum.bit) attributes {qnode} { - - // CHECK: {{%.+}} = ion.ion - - %1 = quantum.alloc( 3) : !quantum.reg - - // CHECK: [[qubit0:%.+]] = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit - // CHECK: [[qubit1:%.+]] = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit - // CHECK: [[qubit2:%.+]] = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit - %2 = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit - %3 = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit - %4 = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit - - // CHECK: [[ms1out:%.+]]:2 = ion.parallelprotocol([[qubit0]], [[qubit1]]) : !quantum.bit, !quantum.bit { - - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): - // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.230000e+00 : f64 - // CHECK-NEXT: [[timems1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [9, 10, 11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 5.660000e+00 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [-9, -10, -11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 3.4599999999999995 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [-9, -10, -11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 4.560000e+00 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [9, 10, 11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 8.960000e+00 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [-9, -10, -11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 1.230000e+00 : f64, - // CHECK-SAME: detuning = 0.15999999999999925 : f64, - // CHECK-SAME: polarization = [7, 8, 9], - // CHECK-SAME: wavevector = [-9, -10, -11]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit - // CHECK-NEXT: } - %5:2 = quantum.custom "MS"(%arg0) %2, %3 : !quantum.bit, !quantum.bit - - // CHECK: [[ms2out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#0, [[qubit2]]) : !quantum.bit, !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): - // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 4.560000e+00 : f64 - // CHECK-NEXT: [[timems2:%.+]] = arith.divf %arg0, [[rabi2]] : f64 - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 7.8899999999999996 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [-3, 4, 5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 8.990000e+00 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [3, -4, -5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 6.7899999999999991 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [3, -4, -5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 7.8899999999999996 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [-3, 4, 5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 1.559000e+01 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [3, -4, -5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 4.560000e+00 : f64, - // CHECK-SAME: detuning = 0.1899999999999995 : f64, - // CHECK-SAME: polarization = [1, 2, 3], - // CHECK-SAME: wavevector = [3, -4, -5]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit - // CHECK-NEXT: } - %6:2 = quantum.custom "MS"(%arg0) %5#0, %4 : !quantum.bit, !quantum.bit - - // CHECK: [[ms3out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#1, [[ms2out]]#1) : !quantum.bit, !quantum.bit { - // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): - // CHECK-NEXT: [[rabi3:%.+]] = arith.constant 99.989999999999994 : f64 - // CHECK-NEXT: [[timems3:%.+]] = arith.divf %arg0, [[rabi3]] : f64 - // CHECK-NEXT: [[p1:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 1.001000e+02 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [-42, -37, -43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: [[p2:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 1.045000e+02 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [42, 37, 43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: [[p3:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 95.699999999999989 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [42, 37, 43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: [[p4:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 0 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 1.001000e+02 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [-42, -37, -43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: [[p5:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 1.078000e+02 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [42, 37, 43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: [[p6:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { - // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, - // CHECK-SAME: rabi = 99.989999999999994 : f64, - // CHECK-SAME: detuning = 92.399999999999991 : f64, - // CHECK-SAME: polarization = [37, 42, 43], - // CHECK-SAME: wavevector = [42, 37, 43]>, - // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse - // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit - // CHECK-NEXT: } - %7:2 = quantum.custom "MS"(%arg0) %5#1, %6#1 : !quantum.bit, !quantum.bit - return %6#0, %7#0, %7#1: !quantum.bit, !quantum.bit, !quantum.bit -} From ff832a97d27aa826080a753f513489a555f50f4b Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:46:42 -0500 Subject: [PATCH 28/61] Add __catalyst__oqd__modes to runtime --- runtime/include/OQDRuntimeCAPI.h | 1 + runtime/lib/backend/oqd/OQDDevice.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/include/OQDRuntimeCAPI.h b/runtime/include/OQDRuntimeCAPI.h index 68d3de09c8..0c68d92adf 100644 --- a/runtime/include/OQDRuntimeCAPI.h +++ b/runtime/include/OQDRuntimeCAPI.h @@ -44,6 +44,7 @@ struct Pulse { void __catalyst__oqd__rt__initialize(); void __catalyst__oqd__rt__finalize(); void __catalyst__oqd__ion(const std::string &ion_specs); +void __catalyst__oqd__modes(const std::vector &phonon_specs); Pulse *__catalyst__oqd__pulse(QUBIT *qubit, double duration, double phase, Beam *beam); void __catalyst__oqd__ParallelProtocol(Pulse **pulses, size_t n); diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index 3cd6be65cc..8f0a68e2b7 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -26,6 +26,7 @@ auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector for (size_t i = 0; i < num_qubits; i++) { __catalyst__oqd__ion(this->ion_specs); } + __catalyst__oqd__modes(this->phonon_specs); // need to return a vector from 0 to num_qubits std::vector result(num_qubits); @@ -37,6 +38,7 @@ auto OQDDevice::AllocateQubits(size_t num_qubits) -> std::vector void OQDDevice::ReleaseAllQubits() { this->ion_specs = ""; + this->phonon_specs.clear(); this->qubit_manager.ReleaseAll(); } @@ -79,7 +81,7 @@ void OQDDevice::NamedOperation(const std::string &name, const std::vector &eigvals, DataView &counts, const std::vector &wires, size_t shots) { - RT_FAIL("Unsupported functionality"); + return; } void OQDDevice::PrintState() { RT_FAIL("Unsupported functionality"); } From 7275b0dc054f3784124c2a0a914cb83153eedc74 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 17:54:47 -0500 Subject: [PATCH 29/61] Add __catalyst__oqd__modes implementation --- runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp | 10 +++++++++- runtime/lib/backend/oqd/OQDDevice.hpp | 25 +++++++++++++++++++++---- runtime/tests/Test_OQDDevice.cpp | 12 ++++++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp b/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp index e0bf9be005..43b1785098 100644 --- a/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp +++ b/runtime/lib/OQDcapi/OQDRuntimeCAPI.cpp @@ -65,7 +65,8 @@ void __catalyst__oqd__rt__initialize() json system = R"({ "class_": "System", - "ions": [] + "ions": [], + "modes": [] })"_json; (*JSON)["system"] = system; @@ -94,6 +95,13 @@ void __catalyst__oqd__ion(const std::string &ion_specs) (*JSON)["system"]["ions"].push_back(json::parse(ion_specs)); } +void __catalyst__oqd__modes(const std::vector &phonon_specs) +{ + for (auto phonon_spec : phonon_specs) { + (*JSON)["system"]["modes"].push_back(json::parse(phonon_spec)); + } +} + Pulse *__catalyst__oqd__pulse(QUBIT *qubit, double duration, double phase, Beam *beam) { size_t wire = reinterpret_cast(qubit); diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index 7226da9de4..f3a1cf968e 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -45,6 +45,7 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { bool tape_recording{false}; size_t device_shots; std::string ion_specs; + std::vector phonon_specs; std::unordered_map device_kwargs; @@ -63,12 +64,28 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { __catalyst__oqd__rt__initialize(); // The OQD kwarg string format is: - // deviceKwargs.str() + "ION:" + std::string(ion_json.dump()) - // where deviceKwargs us the usual kwargs like {'shots': 0, 'mcmc': False} - // and ion_json is a JSON spec string for the ion + // deviceKwargs.str() + "ION:" + std::string(ion_json.dump()) + "PHONON:" + + // std::string(phonon_json1.dump()) + ... where deviceKwargs are the usual keyword arguments + // like {'shots': 0, 'mcmc': False}, ion_json is a JSON string specifying the ion + // configuration, and phonon_json1, phonon_json2, etc. are JSON strings specifying phonon + // configurations. std::string ion_token = "ION:"; + std::string phonon_token = "PHONON:"; size_t ion_token_pos = kwargs.find(ion_token); - ion_specs = kwargs.substr(ion_token_pos + ion_token.length()); + if (ion_token_pos != std::string::npos) { + size_t ion_start_pos = ion_token_pos + ion_token.length(); + size_t phonon_token_pos = kwargs.find(phonon_token); + ion_specs = kwargs.substr(ion_start_pos, phonon_token_pos - ion_start_pos); + } + + phonon_specs.clear(); + size_t phonon_token_pos = kwargs.find(phonon_token); + while (phonon_token_pos != std::string::npos) { + size_t phonon_start_pos = phonon_token_pos + phonon_token.length(); + phonon_token_pos = kwargs.find(phonon_token, phonon_start_pos); + phonon_specs.push_back( + kwargs.substr(phonon_start_pos, phonon_token_pos - phonon_start_pos)); + } device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs.substr(0, ion_token_pos)); device_shots = device_kwargs.contains("shots") diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index f59336bb31..1554cc03ab 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -64,6 +64,13 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "class_": "AtomicCircuit", "system": { "class_": "System", + "modes":[ + { + "class_": "Phonon", + "eigenvector": [0.0,0.0,1.0], + "energy": 3.3 + } + ], "ions": [ { "class_": "Ion", @@ -857,6 +864,11 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") 0.0, 0.0 ] + }PHONON: + { + "class_": "Phonon", + "eigenvector": [0.0,0.0,1.0], + "energy": 3.3 })"}; size_t num_qubits = 2; From 0644a7b4d82f180909968d24bef97b04a8920010 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 13 Feb 2025 19:13:41 -0500 Subject: [PATCH 30/61] fix rebase mistake --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 89d7c0c850..f4404c4148 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -170,7 +170,7 @@ struct IonOpPattern : public OpConversionPattern { {"einsteinA", transitionAttr.getEinsteinA().getValue().convertToDouble()}, {"level1", level1}, {"level2", level2}, - {"label", level0_label + "->" + level1_label}}; + {"label", level0_label + "->" + level1_label}, {"multipole", multipole}}; ion_json["transitions"].push_back(this_transition); } From a92fbce1e323de3f26e41a00e14c72d9f3b28bf3 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 14:15:42 -0500 Subject: [PATCH 31/61] Fixed the rest of lit test --- mlir/test/Ion/QuantumToIon.mlir | 189 ++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index 7ee2f6ff21..770562ced6 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -241,3 +241,192 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} %7:2 = quantum.custom "MS"(%arg0) %6, %3 : !quantum.bit, !quantum.bit return %7#0: !quantum.bit } + + +// ----- + + +// CHECK-LABEL: example_ion_three_qubit +func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, !quantum.bit) attributes {qnode} { + + // CHECK: {{%.+}} = ion.ion + + %1 = quantum.alloc( 3) : !quantum.reg + + // CHECK: [[qubit0:%.+]] = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit + // CHECK: [[qubit1:%.+]] = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit + // CHECK: [[qubit2:%.+]] = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit + %2 = quantum.extract %1[ 0] : !quantum.reg -> !quantum.bit + %3 = quantum.extract %1[ 1] : !quantum.reg -> !quantum.bit + %4 = quantum.extract %1[ 2] : !quantum.reg -> !quantum.bit + + // CHECK: [[ms1out:%.+]]:2 = ion.parallelprotocol([[qubit0]], [[qubit1]]) : !quantum.bit, !quantum.bit { + + // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.230000e+00 : f64 + // CHECK-NEXT: [[timems1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 4.560000e+00 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 5.660000e+00 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 3.4599999999999995 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 4.560000e+00 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [9, 10, 11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 8.960000e+00 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 1.230000e+00 : f64, + // CHECK-SAME: detuning = 0.15999999999999925 : f64, + // CHECK-SAME: polarization = [7, 8, 9], + // CHECK-SAME: wavevector = [-9, -10, -11]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: } + %5:2 = quantum.custom "MS"(%arg0) %2, %3 : !quantum.bit, !quantum.bit + + // CHECK: [[ms2out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#0, [[qubit2]]) : !quantum.bit, !quantum.bit { + // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 4.560000e+00 : f64 + // CHECK-NEXT: [[timems2:%.+]] = arith.divf %arg0, [[rabi2]] : f64 + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 7.8899999999999996 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [-3, 4, 5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 8.990000e+00 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 6.7899999999999991 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 7.8899999999999996 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [-3, 4, 5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 1.559000e+01 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 4.560000e+00 : f64, + // CHECK-SAME: detuning = 0.1899999999999995 : f64, + // CHECK-SAME: polarization = [1, 2, 3], + // CHECK-SAME: wavevector = [3, -4, -5]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} + // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: } + %6:2 = quantum.custom "MS"(%arg0) %5#0, %4 : !quantum.bit, !quantum.bit + + // CHECK: [[ms3out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#1, [[ms2out]]#1) : !quantum.bit, !quantum.bit { + // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT: [[rabi3:%.+]] = arith.constant 99.989999999999994 : f64 + // CHECK-NEXT: [[timems3:%.+]] = arith.divf %arg0, [[rabi3]] : f64 + // CHECK-NEXT: [[p1:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 1.001000e+02 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [-42, -37, -43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: [[p2:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 1.045000e+02 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: [[p3:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 95.699999999999989 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: [[p4:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 0 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 1.001000e+02 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [-42, -37, -43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: [[p5:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 1.078000e+02 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: [[p6:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { + // CHECK-SAME: beam = #ion.beam< + // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: rabi = 99.989999999999994 : f64, + // CHECK-SAME: detuning = 92.399999999999991 : f64, + // CHECK-SAME: polarization = [37, 42, 43], + // CHECK-SAME: wavevector = [42, 37, 43]>, + // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse + // CHECK-NEXT: ion.yield %arg1, %arg2 : !quantum.bit, !quantum.bit + // CHECK-NEXT: } + %7:2 = quantum.custom "MS"(%arg0) %5#1, %6#1 : !quantum.bit, !quantum.bit + return %6#0, %7#0, %7#1: !quantum.bit, !quantum.bit, !quantum.bit +} From 5923391c9d72506f34505b9367c63562f182ff15 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 17:20:50 -0500 Subject: [PATCH 32/61] Fix phonons in database --- mlir/include/Ion/IR/IonOps.td | 2 +- .../Ion/Transforms/oqd_database_managers.hpp | 11 +-- .../lib/Ion/Transforms/ConversionPatterns.cpp | 2 +- mlir/lib/Ion/Transforms/quantum_to_ion.cpp | 5 +- mlir/test/Ion/QuantumToIon.mlir | 6 +- .../oqd_gate_decomposition_parameters.toml | 76 +++++++++++++++---- 6 files changed, 75 insertions(+), 27 deletions(-) diff --git a/mlir/include/Ion/IR/IonOps.td b/mlir/include/Ion/IR/IonOps.td index 6e4ad8a1c8..c686a43146 100644 --- a/mlir/include/Ion/IR/IonOps.td +++ b/mlir/include/Ion/IR/IonOps.td @@ -122,7 +122,7 @@ def PhononAttr : Ion_Attr<"Phonon", "phonon"> { let parameters = (ins "mlir::FloatAttr":$energy, - "mlir::DenseF64ArrayAttr": $eignevector + "mlir::DenseF64ArrayAttr": $eigenvector ); let assemblyFormat = "`<` struct(params) `>`"; diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index f8a42b0a61..4216be20aa 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -29,7 +29,7 @@ namespace ion { class OQDDatabaseManager { public: OQDDatabaseManager(const std::string &DeviceTomlLoc, const std::string &QubitTomlLoc, - const std::string &Gate2PulseDecompTomlLoc) + const std::string &Gate2PulseDecompTomlLoc, size_t n_qubits) { sourceTomlDevice = toml::parse_file(DeviceTomlLoc); sourceTomlQubit = toml::parse_file(QubitTomlLoc); @@ -42,7 +42,7 @@ class OQDDatabaseManager { loadBeams1Params(); loadBeams2Params(); - loadPhononParams(); + loadPhononParams(n_qubits); loadIonParams(); } @@ -106,9 +106,10 @@ class OQDDatabaseManager { } } - void loadPhononParams() - { - toml::node_view phononsToml = sourceTomlGateDecomposition["phonons"]; + void loadPhononParams(size_t n_qubits) + { + std::string phonon_str = "phonons" + std::to_string(n_qubits); + toml::node_view phononsToml = sourceTomlGateDecomposition[phonon_str]; size_t numPhonons = phononsToml.as_array()->size(); auto parseSingleDirection = [](auto direction) { diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index f4404c4148..3e2a8cc475 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -205,7 +205,7 @@ struct ModesOpPattern : public OpConversionPattern { "eigenvector" : [] })"_json; phonon_json["energy"] = phononAttr.getEnergy().getValue().convertToDouble(); - auto eigenvector = phononAttr.getEignevector(); + auto eigenvector = phononAttr.getEigenvector(); for (int j = 0; j < eigenvector.size(); j++) { phonon_json["eigenvector"].push_back(eigenvector[j]); } diff --git a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp index 74a344f9c7..add92d3821 100644 --- a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp +++ b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp @@ -84,8 +84,11 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { target.addIllegalOp(); target.addLegalDialect(); target.markUnknownOpDynamicallyLegal([](Operation *) { return true; }); + + auto allocOp = *op.getOps().begin(); + auto nQubits = allocOp.getNqubitsAttr().value(); - OQDDatabaseManager dataManager(DeviceTomlLoc, QubitTomlLoc, Gate2PulseDecompTomlLoc); + OQDDatabaseManager dataManager(DeviceTomlLoc, QubitTomlLoc, Gate2PulseDecompTomlLoc, nQubits); if (LoadIon) { // FIXME(?): we only load Yb171 ion since the hardware ion species is unlikely to change diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index 770562ced6..e1d85c6732 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -92,15 +92,15 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: modes = [ // CHECK-SAME: #ion.phonon< // CHECK-SAME: energy = 1.100000e+00 : f64, - // CHECK-SAME: eignevector = [1.000000e+00, 0.000000e+00, 0.000000e+00] + // CHECK-SAME: eigenvector = [1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00] // CHECK-SAME: >, // CHECK-SAME: #ion.phonon< // CHECK-SAME: energy = 2.200000e+00 : f64, - // CHECK-SAME: eignevector = [0.000000e+00, 1.000000e+00, 0.000000e+00] + // CHECK-SAME: eigenvector = [0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00] // CHECK-SAME: >, // CHECK-SAME: #ion.phonon< // CHECK-SAME: energy = 3.300000e+00 : f64, - // CHECK-SAME: eignevector = [0.000000e+00, 0.000000e+00, 1.000000e+00] + // CHECK-SAME: eigenvector = [0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00] // CHECK-SAME: > // CHECK-SAME: ] // CHECK-SAME: } diff --git a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml index 5d8c5ae2ea..a5b380f7e0 100644 --- a/mlir/test/Ion/oqd_gate_decomposition_parameters.toml +++ b/mlir/test/Ion/oqd_gate_decomposition_parameters.toml @@ -72,46 +72,90 @@ polarization = [37,42,43] wavevector = [-42,-37,-43] -# Phonons +# Phonon modes # Each qubit has a phonon triplet (x,y,z) # A list of phonon triplets, one triplet per qubit, is stored here # On a single direction, a phonon has a calibrated energy. +# phonons1 are the phonons modes of a single-ion system. +# phonons2 are the phonons modes of a two-ion system. +# phonons3 are the phonons modes of a three-ion system. # ------- -[[phonons]] +[[phonons1]] energy = 1.1 eigenvector = [1.0, 0.0, 0.0] -[[phonons]] +[[phonons1]] energy = 2.2 eigenvector = [0.0, 1.0, 0.0] -[[phonons]] +[[phonons1]] energy = 3.3 eigenvector = [0.0, 0.0, 1.0] -[[phonons]] + +[[phonons2]] +energy = 1.1 +eigenvector = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] + +[[phonons2]] +energy = 2.2 +eigenvector = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0] + +[[phonons2]] +energy = 3.3 +eigenvector = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0] + + +[[phonons2]] energy = 4.4 -eigenvector = [1.0, 0.0, 0.0] +eigenvector = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0] -[[phonons]] +[[phonons2]] energy = 5.5 -eigenvector = [0.0, 1.0, 0.0] +eigenvector = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0] -[[phonons]] +[[phonons2]] energy = 6.6 -eigenvector = [0.0, 0.0, 1.0] +eigenvector = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0] + -[[phonons]] +[[phonons3]] +energy = 1.1 +eigenvector = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0] + +[[phonons3]] +energy = 2.2 +eigenvector = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0] + +[[phonons3]] +energy = 3.3 +eigenvector = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0] + + +[[phonons3]] +energy = 4.4 +eigenvector = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0] + +[[phonons3]] +energy = 5.5 +eigenvector = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0] + +[[phonons3]] +energy = 6.6 +eigenvector = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0] + + +[[phonons3]] energy = 7.7 -eigenvector = [1.0, 0.0, 0.0] +eigenvector = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0] -[[phonons]] +[[phonons3]] energy = 8.8 -eigenvector = [0.0, 1.0, 0.0] +eigenvector = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0] -[[phonons]] +[[phonons3]] energy = 9.9 -eigenvector = [0.0, 0.0, 1.0] +eigenvector = [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0] From f0147eae2e3cd86a1be4487551aaee1bd659fa44 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 17:21:30 -0500 Subject: [PATCH 33/61] revert changes added by mistake --- frontend/catalyst/third_party/oqd/oqd_device.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/frontend/catalyst/third_party/oqd/oqd_device.py b/frontend/catalyst/third_party/oqd/oqd_device.py index d2f06328a2..01c229374b 100644 --- a/frontend/catalyst/third_party/oqd/oqd_device.py +++ b/frontend/catalyst/third_party/oqd/oqd_device.py @@ -47,16 +47,7 @@ def get_c_interface(): return "oqd", lib_path - def __init__(self, wires, shots=None, backend="default", **kwargs): - self.device_toml = kwargs.pop("device_toml", []) - self.qubit_toml = kwargs.pop("qubit_toml", []) - self.gate_toml = kwargs.pop("gate_toml", []) - if not self.device_toml: - raise ValueError("device-toml file must be provided.") - if not self.qubit_toml: - raise ValueError("qubit-toml file must be provided.") - if not self.gate_toml: - raise ValueError("gate-toml file must be provided.") + def __init__(self, wires, shots, backend="default", **kwargs): self._backend = backend _check_backend(backend=backend) super().__init__(wires=wires, shots=shots, **kwargs) From a4dc00255a7ec35d4470a0d1efbac257ba4deac8 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 17:40:45 -0500 Subject: [PATCH 34/61] remove label from transition in toml --- .../test_oqd/oqd/calibration_data/device.toml | 743 ++++++++++++++++++ mlir/test/Ion/oqd_qubit_parameters.toml | 3 - 2 files changed, 743 insertions(+), 3 deletions(-) create mode 100644 frontend/test/test_oqd/oqd/calibration_data/device.toml diff --git a/frontend/test/test_oqd/oqd/calibration_data/device.toml b/frontend/test/test_oqd/oqd/calibration_data/device.toml new file mode 100644 index 0000000000..42c9d77588 --- /dev/null +++ b/frontend/test/test_oqd/oqd/calibration_data/device.toml @@ -0,0 +1,743 @@ +# OQD Device Parameters +# ~~~~~~~~~~~~~~~~~~~~~ +# +# A database containing parameters relating to the hardware and experiment workflow used in an Open +# Quantum Design (OQD) trapped-ion quantum computer device. + +oqd_config_schema = "v0.1" + +[parameters.N_load] +description = "Number of ions" +stage = "Loading" +process = "Ablation" +equation = "" +value = "1" +unit = "" + +[parameters.w_ablation] +description = "Ablation laser frequency" +stage = "Loading" +process = "Ablation" +equation = "" +value = "532" +unit = "nm" + +[parameters.t_ablation] +description = "Ablation laser pulse duration" +stage = "Loading" +process = "Ablation" +equation = "" +value = "1" +unit = "ns" + +[parameters.I_ablation] +description = "Ablation laser intensity" +stage = "Loading" +process = "Ablation" +equation = "" +value = "0.57" +unit = "J/cm^2" + +[parameters.rate_ablation] +description = "Ablation laser pulse rate" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters.N_ablation] +description = "Ablation laser # of pulses" +stage = "Loading" +process = "Ablation" +equation = "rate_ablation * t_ablation" +value = "" +unit = "" + +[parameters."w_ionization^1"] +description = "Ionization laser 1 frequency" +stage = "Loading" +process = "Ablation" +equation = "" +value = "554" +unit = "nm" + +[parameters."t_ionization^1"] +description = "Ionization laser 1 pulse duration" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters."I_ionization^1"] +description = "Ionization laser 1 intensity" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters."w_ionization^2"] +description = "Ionization laser 2 frequency" +stage = "Loading" +process = "Ablation" +equation = "" +value = "390" +unit = "nm" + +[parameters."t_ionization^2"] +description = "Ionization laser 2 pulse duration" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters."I_ionization^2"] +description = "Ionization laser 2 intensity" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters.x_target] +description = "Target x position" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters.y_target] +description = "Target y position" +stage = "Loading" +process = "Ablation" +equation = "" +value = "" +unit = "" + +[parameters.N_trap] +description = "Number of ions" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "1" +unit = "" + +[parameters.m] +description = "Ion mass" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "133" +unit = "AMU" + +[parameters.q] +description = "Ion charge" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "+e" +unit = "" + +[parameters.w_x] +description = "Radial frequency, x" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "" +unit = "" + +[parameters.w_y] +description = "Radial frequency, y" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "" +unit = "" + +[parameters.w_z] +description = "Axial frequency" +stage = "Trapping" +process = "Ion characteristics" +equation = "" +value = "" +unit = "" + +[parameters.V_RFT] +description = "RF trapping voltage" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "250" +unit = "V" + +[parameters.V_RFC] +description = "RF confinement voltage" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "250" +unit = "V" + +[parameters.Omega_RF] +description = "RF signal frequency" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "36" +unit = "MHz" + +[parameters."V_DC^X"] +description = "DC electrode voltage (x X electrodes)" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "94" +unit = "channels" + +[parameters.micromotion_x] +description = "Micromotion in x" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.micromotion_y] +description = "Micromotion in y" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.micromotion_z] +description = "Micromotion in z" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.theta] +description = "Principal axes rotation, theta" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.phi] +description = "Principal axes rotation, phi" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.position_N] +description = "Ion equilibrium position(s)" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters."mode_x^N"] +description = "Radial motional mode(s), x" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters."mode_y^N"] +description = "Radial motional mode(s), y" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters."mode_z^N"] +description = "Axial motional mode(s)" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.TODO] +description = "Engineered voltage fluctuations" +stage = "Trapping" +process = "Electric Potential" +equation = "" +value = "" +unit = "" + +[parameters.n] +description = "Phonon cooling target" +stage = "Trapping" +process = "Cooling" +equation = "" +value = "Doppler limit" +unit = "" + +[parameters.n_doppler] +description = "Doppler limit" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "Doppler limit" +unit = "" + +[parameters.w_doppler] +description = "Doppler cooling laser frequency" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "493 nm - 7.506 GHz, 493 nm + 4.259 GHz" +unit = "" + +[parameters.sigma_doppler] +description = "Doppler cooling laser polarization(s)" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.I_doppler_saturation] +description = "Doppler cooling laser saturation intensity" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.I_doppler] +description = "Doppler cooling laser intensity" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "<< I_Doppler_saturation" +unit = "" + +[parameters.w_doppler_sideband_1] +description = "Doppler cooling laser sideband 1 frequency modulation" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.P_doppler_1] +description = "Doppler cooling laser sideband 1 power" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.w_doppler_sideband_2] +description = "Doppler cooling laser sideband 2 frequency modulation" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.P_doppler_2] +description = "Doppler cooling laser sideband 2 power" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.w_doppler_repump] +description = "Doppler cooling repump laser frequency" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "650 nm - 1.840 GHz, 650 nm - 0.903 GHz" +unit = "" + +[parameters.sigma_doppler_repump] +description = "Doppler cooling repump laser polarization(s)" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.I_Doppler_saturation_repump] +description = "Doppler cooling repump laser saturation intensity" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.I_Doppler_repump] +description = "Doppler cooling repump laser intensity" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.P_Dopper_sideband] +description = "Doppler cooling repump sideband power" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.t_Doppler] +description = "Doppler cooling time duration" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters."Delta_Doppler^?"] +description = "Detuning(s)?" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.TODO_45] +description = "Narrow linewidth cooling laser frequency" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.TODO_46] +description = "Narrow linewidth cooling laser polarization" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.TODO_47] +description = "Narrow linewidth cooling laser power" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.TODO_48] +description = "Narrow linewidth cooling laser saturation intensity" +stage = "Trapping" +process = "Cooling (Doppler)" +equation = "" +value = "" +unit = "" + +[parameters.n_rsc] +description = "RSB cooling limit" +stage = "Trapping" +process = "Cooling (Resolved sideband)" +equation = "" +value = "" +unit = "" + +[parameters.omega_RSBC] +description = "RSB cooling laser frequency" +stage = "Trapping" +process = "Cooling (Resolved sideband)" +equation = "" +value = "" +unit = "" + +[parameters.sigma_RSBC] +description = "RSB cooling laser polarization(s)" +stage = "Trapping" +process = "Cooling (Resolved sideband)" +equation = "" +value = "" +unit = "" + +[parameters.I_RSBC_saturation] +description = "RSB cooling laser saturation intensity" +stage = "Trapping" +process = "Cooling (Resolved sideband)" +equation = "" +value = "" +unit = "" + +[parameters.I_RSBC] +description = "RSB cooling laser intensity" +stage = "Trapping" +process = "Cooling (Resolved sideband)" +equation = "" +value = "" +unit = "" + +[parameters.TODO_54] +description = "TODO" +stage = "Trapping" +process = "Cooling (EIT)" +equation = "" +value = "" +unit = "" + +[parameters.omega_preparation] +description = "Optical pumping laser frequency" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "493" +unit = "nm" + +[parameters.sigma_opt_pump] +description = "Optical pumping laser polarization(s)" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.I_opt_pump_saturation] +description = "Optical pumping laser saturation intensity" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.I_opt_pump] +description = "Optical pumping laser intensity" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.TODO_59] +description = "Optical pumping laser sideband frequency" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.TODO_60] +description = "Optical pumping laser sideband power" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.omega_RSB_repump] +description = "Optical pumping repump laser frequency" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "650" +unit = "nm" + +[parameters.I_RSB_repump_saturation] +description = "Optical pumping repump laser saturation intensity" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.I_RSB_repump] +description = "Optical pumping repump laser intensity" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.TODO_64] +description = "Optical pumping repump laser sideband frequency" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.TODO_65] +description = "Optical pumping repumplaser sideband power" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.TODO_66] +description = "Detuning(s)?" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.t_RSBC] +description = "Optical pumping time duration" +stage = "Initialization" +process = "State Preparation" +equation = "" +value = "" +unit = "" + +[parameters.omega_q] +description = "Qubit Carrier Frequency" +stage = "Experiment" +process = "X Gate" +equation = "2*pi*(12.6 GHz)" +value = "" +unit = "" + +[parameters.omega_e] +description = "Excited State Frequency" +stage = "Experiment" +process = "X Gate" +equation = "" +value = "" +unit = "" + +[parameters.omega_A] +description = "Raman Frequency A" +stage = "Experiment" +process = "X Gate" +equation = "" +value = "" +unit = "" + +[parameters.omega_B] +description = "Raman Frequency B" +stage = "Experiment" +process = "X Gate" +equation = "omega_e + delta - omega_q" +value = "" +unit = "" + +[parameters.Delta] +description = "Raman Detuning" +stage = "Experiment" +process = "X Gate" +equation = "omega_e - omega_a" +value = "" +unit = "" + +[parameters.Omega_A] +description = "" +stage = "Experiment" +process = "X Gate" +equation = "Omega_A = Omega_B" +value = "" +unit = "" + +[parameters.Omega_B] +description = "" +stage = "Experiment" +process = "X Gate" +equation = "Omega_A = Omega_B" +value = "" +unit = "" + +[parameters.Omega] +description = "Rabi Frequency" +stage = "Experiment" +process = "X Gate" +equation = "(omega_a*Omega_B)/(2*Delta)" +value = "" +unit = "" + +[parameters.gate_phi] +description = "Gate Phase" +stage = "Experiment" +process = "X Gate" +equation = "TODO" +value = "0" +unit = "rad" + +[parameters.phi_a] +description = "Laser A phase" +stage = "Experiment" +process = "X Gate" +equation = "phi_a = phi_b =0" +value = "" +unit = "" + +[parameters.phi_b] +description = "Laser B phase" +stage = "Experiment" +process = "X Gate" +equation = "phi_a = phi_b =0" +value = "" +unit = "" + +[parameters.t_gate] +description = "Gate Duration" +stage = "Experiment" +process = "X Gate" +equation = "" +value = "" +unit = "" + +[parameters.H] +description = "Hamiltonian" +stage = "Experiment" +process = "X Gate" +equation = "" +value = "" +unit = "" + +[parameters.omega_measurement] +description = "Measurement laser frequency" +stage = "Detection" +process = "Measurement" +equation = "" +value = "493" +unit = "nm" + +[parameters.I_measurement] +description = "Measurement laser saturation" +stage = "Detection" +process = "Measurement" +equation = "I_saturation" +value = "" +unit = "" + +[parameters.t_measurement] +description = "Measurement duration" +stage = "Detection" +process = "Measurement" +equation = "" +value = "" +unit = "" + +[parameters.omega_repump] +description = "Measurement repump frequency" +stage = "Detection" +process = "Measurement" +equation = "" +value = "650" +unit = "nm" + +[parameters.I_repump] +description = "Measurement repump Intensity" +stage = "Detection" +process = "Measurement" +equation = "" +value = "Doppler limit" +unit = "" diff --git a/mlir/test/Ion/oqd_qubit_parameters.toml b/mlir/test/Ion/oqd_qubit_parameters.toml index 6ae157718c..09bec8414f 100644 --- a/mlir/test/Ion/oqd_qubit_parameters.toml +++ b/mlir/test/Ion/oqd_qubit_parameters.toml @@ -57,21 +57,18 @@ levels.estate.spin_orbital_nuclear_magnetization = -5.0 levels.estate.energy = 811.52e12 [ions.Yb171.transitions.downstate_upstate] -label = "downstate->upstate" level1 = "downstate" level2 = "upstate" einstein_a = 1.1 multipole = "M1" [ions.Yb171.transitions.downstate_estate] -label = "downstate->estate" level1 = "downstate" level2 = "estate" einstein_a = 2.2 multipole = "E2" [ions.Yb171.transitions.estate_upstate] -label = "estate->upstate" level1 = "estate" level2 = "upstate" einstein_a = 3.3 From 6eef988d83816bf1bb53be918ac88e7ba2e9bf63 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 18:09:47 -0500 Subject: [PATCH 35/61] add estate2 --- mlir/test/Ion/oqd_qubit_parameters.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mlir/test/Ion/oqd_qubit_parameters.toml b/mlir/test/Ion/oqd_qubit_parameters.toml index 09bec8414f..08f6ed4389 100644 --- a/mlir/test/Ion/oqd_qubit_parameters.toml +++ b/mlir/test/Ion/oqd_qubit_parameters.toml @@ -56,6 +56,16 @@ levels.estate.spin_orbital_nuclear = 4.5 levels.estate.spin_orbital_nuclear_magnetization = -5.0 levels.estate.energy = 811.52e12 +levels.estate2.label = "estate2" +levels.estate2.principal = 5 +levels.estate2.spin = 0.5 +levels.estate2.orbital = 1.0 +levels.estate2.nuclear = 0.5 +levels.estate2.spin_orbital = 0.5 +levels.estate2.spin_orbital_nuclear = 1.0 +levels.estate2.spin_orbital_nuclear_magnetization = 1.0 +levels.estate2.energy = 1256.637 + [ions.Yb171.transitions.downstate_upstate] level1 = "downstate" level2 = "upstate" From e624db8fff5f547291481c9767ddd8e3daf2a5b3 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Tue, 18 Feb 2025 18:10:45 -0500 Subject: [PATCH 36/61] modify database to include estate2 --- mlir/include/Ion/Transforms/oqd_database_managers.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index 4216be20aa..47b672be64 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -158,9 +158,9 @@ class OQDDatabaseManager { std::string level2 = transition_entry["level2"].as_string()->get(); std::string multipole = transition_entry["multipole"].as_string()->get(); - std::set levelEncodings{"downstate", "upstate", "estate"}; + std::set levelEncodings{"downstate", "upstate", "estate", "estate2"}; assert((levelEncodings.count(level1) & levelEncodings.count(level2)) && - "Only \"downstate\", \"upstate\" and \"estate\" are allowed in the atom's " + "Only \"downstate\", \"upstate\", \"estate\" and \"estate2\" are allowed in the atom's " "transition levels."); return Transition(level1, level2, multipole, einstein_a); @@ -179,7 +179,8 @@ class OQDDatabaseManager { Level downstate = parseSingleLevel(data->at_path("levels")["downstate"]); Level upstate = parseSingleLevel(data->at_path("levels")["upstate"]); Level estate = parseSingleLevel(data->at_path("levels")["estate"]); - std::vector levels{downstate, upstate, estate}; + Level estate2 = parseSingleLevel(data->at_path("levels")["estate2"]); + std::vector levels{downstate, upstate, estate, estate2}; std::vector transitions; auto *transitionsTable = data->at_path("transitions").as_table(); From f3f64766e74e63dc6a746b7b0d2ce50fcf83c836 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 10:35:06 -0500 Subject: [PATCH 37/61] add new transitions after adding the forth estate2 state --- mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index 04e7ca7561..fc0012251e 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -37,7 +37,9 @@ enum LevelTransition { // Encoding of level transitions for a pulse // For example, "DOWN_E" means the transition from downstate to estate DOWN_E = 0, - UP_E = 1, + DOWN_E2 = 1, + UP_E = 2, + UP_E2 = 3, }; /** From a0fea53de0c5cb1e2f3dabf3946c507e88de920e Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 10:42:18 -0500 Subject: [PATCH 38/61] Add test toml files --- .../test_oqd/oqd/calibration_data/gate.toml | 90 ++++++++++++++++++ .../test_oqd/oqd/calibration_data/qubit.toml | 91 +++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 frontend/test/test_oqd/oqd/calibration_data/gate.toml create mode 100644 frontend/test/test_oqd/oqd/calibration_data/qubit.toml diff --git a/frontend/test/test_oqd/oqd/calibration_data/gate.toml b/frontend/test/test_oqd/oqd/calibration_data/gate.toml new file mode 100644 index 0000000000..72f1857596 --- /dev/null +++ b/frontend/test/test_oqd/oqd/calibration_data/gate.toml @@ -0,0 +1,90 @@ +# OQD Gate-Decomposition Parameters +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# A database containing parameters relating to decompositions of gates to pulse operations used in +# an Open Quantum Design (OQD) trapped-ion quantum computer device. + +oqd_config_schema = "v0.1" + + +# Beams +# A beam contains 4 properties that will be calibrated: +# rabi = float, +# detuning = float, +# polarization = int array, +# wavevector = int array, +# +# A pulse operation will consist of a beam, a transition, a phase, a time (duration of application), and a target qubit +# A list of beams is recorded in this toml. +# +# `beams1` are the beams used for single-qubit gates. +# The i-th beams1 is usable on the i-th qubit. +# +# `beams2` are the beams used for 2-qubit gates. +# In a system with n qubits, there are (n choose 2) = n*(n-1)/2 possible two-qubit +# combinations. Each combination is represented by a unique index. For example, in a 4-qubit system, where the qubits are indexed as [0, 1, 2, 3], +# the possible two-qubit combinations and their indices are: +# 0: (0, 1) +# 1: (0, 2) +# 2: (0, 3) +# 3: (1, 2) +# 4: (1, 3) +# 5: (2, 3) +# The i-th beams2 is usable on a gate whose input qubit indices +# correspond to i in the above encoding combination. +# ------- + +[[beams1]] +rabi = 31.4159 +detuning = 157.0796 +polarization = [1,0,0] +wavevector = [0,1,0] + +[[beams1]] +rabi = 31.4159 +detuning = 157.0796 +polarization = [1,0,0] +wavevector = [0,1,0] + +[[beams1]] +rabi = 31.4159 +detuning = 157.0796 +polarization = [1,0,0] +wavevector = [0,1,0] + + +[[beams2]] +rabi = 31.4159 +detuning = 157.0796 +polarization = [7,8,9] +wavevector = [9,10,11] + +[[beams2]] +rabi = 31.4159 +detuning = 7.89 +polarization = [1,2,3] +wavevector = [-3,4,5] + +[[beams2]] +rabi = 31.4159 +detuning = 157.0796 +polarization = [37,42,43] +wavevector = [-42,-37,-43] + + +# Phonon modes +# Each qubit has a phonon triplet (x,y,z) +# A list of phonon triplets, one triplet per qubit, is stored here +# On a single direction, a phonon has a calibrated energy. +# phonons1 are the phonons used for single-qubit gates. +# phonons2 are the phonons used for 2-qubit gates. +# ------- + +[[phonons1]] +energy = 0.1 +eigenvector = [1.0, 0.0, 0.0] + + +[[phonons2]] +energy = 0.1 +eigenvector = [0.7071, 0.0, 0.0, 0.7071, 0, 0] diff --git a/frontend/test/test_oqd/oqd/calibration_data/qubit.toml b/frontend/test/test_oqd/oqd/calibration_data/qubit.toml new file mode 100644 index 0000000000..0c61142575 --- /dev/null +++ b/frontend/test/test_oqd/oqd/calibration_data/qubit.toml @@ -0,0 +1,91 @@ +# OQD Qubit Parameters +# ~~~~~~~~~~~~~~~~~~~~ +# +# A database containing parameters relating to the qubit(s) used in an Open Quantum Design (OQD) +# trapped-ion quantum computer device. + +oqd_config_schema = "v0.1" + +# ----- TODO: Is this needed? -------------------------------------------------- +# [ion.Yb_171_II] +# level.q0_m0 = "0" +# level.q1_m0 = "12.643e9" +# level.q1_m1 = "12.643e9 + 1.4e6" +# level.q1_mneg1 = "12.643e9 - 1.4e6" +# level.e0_m0 = "811.302e12" +# level.e1_m0 = "811.302e12 + 2.105e9" +# level.e1_m1 = "811.302e12 + 2.105e9 + 0.47e6" +# level.e1_mneg1 = "811.302e12 + 2.105e9 - 0.47e6" +# ------------------------------------------------------------------------------ + +# Ions +# ---- + +[ions.Yb171] +mass = 171.0 +charge = +1.0 +position = [0.0, 0.0, 0.0] + +levels.downstate.label = "downstate" +levels.downstate.principal = 6 +levels.downstate.spin = 0.5 +levels.downstate.orbital = 0.0 +levels.downstate.nuclear = 0.5 +levels.downstate.spin_orbital = 0.5 +levels.downstate.spin_orbital_nuclear = 0.0 +levels.downstate.spin_orbital_nuclear_magnetization = 0.0 +levels.downstate.energy = 0.0 + +levels.upstate.label = "upstate" +levels.upstate.principal = 6 +levels.upstate.spin = 0.5 +levels.upstate.orbital = 0.0 +levels.upstate.nuclear = 0.5 +levels.upstate.spin_orbital = 0.5 +levels.upstate.spin_orbital_nuclear = 1.0 +levels.upstate.spin_orbital_nuclear_magnetization = 0.0 +levels.upstate.energy = 62.83185 + +levels.estate.label = "estate" +levels.estate.principal = 5 +levels.estate.spin = 0.5 +levels.estate.orbital = 1.0 +levels.estate.nuclear = 0.5 +levels.estate.spin_orbital = 0.5 +levels.estate.spin_orbital_nuclear = 1.0 +levels.estate.spin_orbital_nuclear_magnetization = -1.0 +levels.estate.energy = 628.3185 + +levels.estate2.label = "estate2" +levels.estate2.principal = 5 +levels.estate2.spin = 0.5 +levels.estate2.orbital = 1.0 +levels.estate2.nuclear = 0.5 +levels.estate2.spin_orbital = 0.5 +levels.estate2.spin_orbital_nuclear = 1.0 +levels.estate2.spin_orbital_nuclear_magnetization = 1.0 +levels.estate2.energy = 1256.637 + +[ions.Yb171.transitions.downstate_estate] +level1 = "downstate" +level2 = "estate" +einstein_a = 1.0 +multipole = "E1" + +[ions.Yb171.transitions.downstate_estate2] +level1 = "downstate" +level2 = "estate2" +einstein_a = 1.0 +multipole = "E1" + +[ions.Yb171.transitions.upstate_estate] +level1 = "upstate" +level2 = "estate" +einstein_a = 1.0 +multipole = "E1" + +[ions.Yb171.transitions.upstate_estate2] +level1 = "upstate" +level2 = "estate2" +einstein_a = 1.0 +multipole = "E1" From a2bafa5d2890da8cd33832fa781e098a471cfe41 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:22:51 -0500 Subject: [PATCH 39/61] Add OpenAPL tests --- .../test_oqd/oqd/test_openapl_generation.py | 115 ++ .../test/test_oqd/oqd/test_single_CNOT.json | 1256 +++++++++++++++++ .../test/test_oqd/oqd/test_single_RX.json | 331 +++++ 3 files changed, 1702 insertions(+) create mode 100644 frontend/test/test_oqd/oqd/test_openapl_generation.py create mode 100644 frontend/test/test_oqd/oqd/test_single_CNOT.json create mode 100644 frontend/test/test_oqd/oqd/test_single_RX.json diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py new file mode 100644 index 0000000000..685f08b50c --- /dev/null +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -0,0 +1,115 @@ +# Copyright 2024 Xanadu Quantum Technologies Inc. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Test the OpenAPL generation.""" + +import json +import os + +import pennylane as qml +import pytest + +from catalyst import qjit +from catalyst.third_party.oqd import OQDDevice + + +class TestOpenAPL: + """Test that the OQD device correctly generates an OpenAPL program.""" + + oqd_pipelines = [ + ( + "device-agnoistic-pipeline", + [ + "enforce-runtime-invariants-pipeline", + "hlo-lowering-pipeline", + "quantum-compilation-pipeline", + "bufferization-pipeline", + ], + ), + ( + "oqd_pipeline", + [ + "func.func(ions-decomposition)", + "func.func(quantum-to-ion{" + + "device-toml-loc=" + + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/device.toml " + + "qubit-toml-loc=" + + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/qubit.toml " + + "gate-to-pulse-toml-loc=" + + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/gate.toml" + + "})", + "convert-ion-to-llvm", + ], + ), + ( + "llvm-dialect-lowering-pipeline", + [ + "llvm-dialect-lowering-pipeline", + ], + ), + ] + + device_toml = "device.toml " + qubit_toml = "qubit.toml " + gate_toml = "gate.toml" + + def test_RX_gate(self): + """Test OpenAPL generation for a circuit with a single RX Gate.""" + oqd_dev = OQDDevice(backend="default", shots=4, wires=1) + + @qjit(pipelines=self.oqd_pipelines) + @qml.qnode(oqd_dev) + def circuit(x): + qml.RX(x, wires=0) + return qml.counts() + + circuit(1.5708) + + with open("/Users/mehrdad.malek/catalyst/__openapl__output.json", "r") as f: + catalyst_json = json.load(f) + + with open( + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_RX.json", "r" + ) as f: + expected_json = json.load(f) + + assert sorted(catalyst_json.items()) == sorted(expected_json.items()) + os.remove("/Users/mehrdad.malek/catalyst/__openapl__output.json") + + def test_CNOT_gate(self): + """Test OpenAPL generation for a circuit with a single CNOT circuit.""" + oqd_dev = OQDDevice(backend="default", shots=4, wires=2) + + @qjit(pipelines=self.oqd_pipelines, keep_intermediate=True) + @qml.qnode(oqd_dev) + def circuit(x): + qml.CNOT(wires=[0, 1]) + return qml.counts() + + circuit(1.5708) + + with open("/Users/mehrdad.malek/catalyst/__openapl__output.json", "r") as f: + catalyst_json = json.load(f) + + with open( + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_CNOT.json", "r" + ) as f: + expected_json = json.load(f) + + assert sorted(catalyst_json.items()) == sorted(expected_json.items()) + os.remove("/Users/mehrdad.malek/catalyst/__openapl__output.json") + + +if __name__ == "__main__": + pytest.main(["-x", __file__]) diff --git a/frontend/test/test_oqd/oqd/test_single_CNOT.json b/frontend/test/test_oqd/oqd/test_single_CNOT.json new file mode 100644 index 0000000000..2b6a39bae4 --- /dev/null +++ b/frontend/test/test_oqd/oqd/test_single_CNOT.json @@ -0,0 +1,1256 @@ +{ + "class_": "AtomicCircuit", + "protocol": { + "class_": "SequentialProtocol", + "sequence": [ + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 3.141592653589793 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + } + ] + }, + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + -1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.1796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 156.9796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 1, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + -1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.1796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 1, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 156.9796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 0, + 1, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 1, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 1, + 0, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.050000042233228924 + } + ] + }, + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + } + ] + }, + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 1, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 3.141592653589793 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 1, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + } + ] + }, + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 3.141592653589793 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.3500002956326025 + } + ] + } + ] + }, + "system": { + "class_": "System", + "ions": [ + { + "charge": 1.0, + "class_": "Ion", + "levels": [ + { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + } + ], + "mass": 171.0, + "position": [ + 0.0, + 0.0, + 0.0 + ], + "transitions": [ + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate2", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate2", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + } + ] + }, + { + "charge": 1.0, + "class_": "Ion", + "levels": [ + { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + } + ], + "mass": 171.0, + "position": [ + 0.0, + 0.0, + 0.0 + ], + "transitions": [ + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate2", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate2", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + } + ] + } + ], + "modes": [ + { + "class_": "Phonon", + "eigenvector": [ + 0.1, + 0.0, + 0.0, + 0.1, + 0.0, + 0.0 + ], + "energy": 0.1 + } + ] + } +} \ No newline at end of file diff --git a/frontend/test/test_oqd/oqd/test_single_RX.json b/frontend/test/test_oqd/oqd/test_single_RX.json new file mode 100644 index 0000000000..c2d1cb9c27 --- /dev/null +++ b/frontend/test/test_oqd/oqd/test_single_RX.json @@ -0,0 +1,331 @@ +{ + "class_": "AtomicCircuit", + "protocol": { + "class_": "SequentialProtocol", + "sequence": [ + { + "class_": "ParallelProtocol", + "sequence": [ + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.05000015915507752 + }, + { + "beam": { + "class_": "Beam", + "detuning": { + "class_": "MathNum", + "value": 157.0796 + }, + "phase": { + "class_": "MathNum", + "value": 0.0 + }, + "polarization": [ + 1, + 0, + 0 + ], + "rabi": { + "class_": "MathNum", + "value": 31.4159 + }, + "target": 0, + "transition": { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + "wavevector": [ + 0, + 1, + 0 + ] + }, + "class_": "Pulse", + "duration": 0.05000015915507752 + } + ] + } + ] + }, + "system": { + "class_": "System", + "ions": [ + { + "charge": 1.0, + "class_": "Ion", + "levels": [ + { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + } + ], + "mass": 171.0, + "position": [ + 0.0, + 0.0, + 0.0 + ], + "transitions": [ + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "downstate->estate2", + "level1": { + "class_": "Level", + "energy": 0.0, + "label": "downstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 0.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 628.3185, + "label": "estate", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": -1.0 + }, + "multipole": "E1" + }, + { + "class_": "Transition", + "einsteinA": 1.0, + "label": "upstate->estate2", + "level1": { + "class_": "Level", + "energy": 62.83185, + "label": "upstate", + "nuclear": 0.5, + "orbital": 0.0, + "principal": 6, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 0.0 + }, + "level2": { + "class_": "Level", + "energy": 1256.637, + "label": "estate2", + "nuclear": 0.5, + "orbital": 1.0, + "principal": 5, + "spin": 0.5, + "spin_orbital": 0.5, + "spin_orbital_nuclear": 1.0, + "spin_orbital_nuclear_magnetization": 1.0 + }, + "multipole": "E1" + } + ] + } + ], + "modes": [ + { + "class_": "Phonon", + "eigenvector": [ + 1.0, + 0.0, + 0.0 + ], + "energy": 0.1 + } + ] + } +} \ No newline at end of file From f9d0e24339fc5a3a25aaee9bf31864135b31d9d1 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:23:38 -0500 Subject: [PATCH 40/61] Add all phonons but only print one for now --- .../test_oqd/oqd/calibration_data/gate.toml | 42 +++++++++++++++---- mlir/lib/Ion/Transforms/quantum_to_ion.cpp | 9 ++-- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/frontend/test/test_oqd/oqd/calibration_data/gate.toml b/frontend/test/test_oqd/oqd/calibration_data/gate.toml index 72f1857596..e431f6f668 100644 --- a/frontend/test/test_oqd/oqd/calibration_data/gate.toml +++ b/frontend/test/test_oqd/oqd/calibration_data/gate.toml @@ -56,20 +56,20 @@ wavevector = [0,1,0] [[beams2]] rabi = 31.4159 detuning = 157.0796 -polarization = [7,8,9] -wavevector = [9,10,11] +polarization = [0,1,0] +wavevector = [-1, 0, 0] [[beams2]] rabi = 31.4159 detuning = 7.89 -polarization = [1,2,3] -wavevector = [-3,4,5] +polarization = [0,1,0] +wavevector = [1, 0, 0] [[beams2]] rabi = 31.4159 detuning = 157.0796 -polarization = [37,42,43] -wavevector = [-42,-37,-43] +polarization = [0,1,0] +wavevector = [1, 0, 0] # Phonon modes @@ -84,7 +84,35 @@ wavevector = [-42,-37,-43] energy = 0.1 eigenvector = [1.0, 0.0, 0.0] +[[phonons1]] +energy = 0.1 +eigenvector = [1.0, 0.0, 0.0] + +[[phonons1]] +energy = 0.1 +eigenvector = [1.0, 0.0, 0.0] + + +[[phonons2]] +energy = 0.1 +eigenvector = [0.1, 0.0, 0.0, 0.1, 0.0, 0.0] + +[[phonons2]] +energy = 0.1 +eigenvector = [0.0, 0.1, 0.0, 0.0, 0.1, 0.0] + +[[phonons2]] +energy = 0.1 +eigenvector = [0.0, 0.0, 0.1, 0.0, 0.0, 0.1] + +[[phonons2]] +energy = 0.1 +eigenvector = [0.1, 0.0, 0.0, 0.1, 0.0, 0.0] + +[[phonons2]] +energy = 0.1 +eigenvector = [0.0, 0.1, 0.0, 0.0, 0.1, 0.0] [[phonons2]] energy = 0.1 -eigenvector = [0.7071, 0.0, 0.0, 0.7071, 0, 0] +eigenvector = [0.0, 0.0, 0.1, 0.0, 0.0, 0.1] diff --git a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp index add92d3821..82b600bacc 100644 --- a/mlir/lib/Ion/Transforms/quantum_to_ion.cpp +++ b/mlir/lib/Ion/Transforms/quantum_to_ion.cpp @@ -84,11 +84,12 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { target.addIllegalOp(); target.addLegalDialect(); target.markUnknownOpDynamicallyLegal([](Operation *) { return true; }); - + auto allocOp = *op.getOps().begin(); auto nQubits = allocOp.getNqubitsAttr().value(); - OQDDatabaseManager dataManager(DeviceTomlLoc, QubitTomlLoc, Gate2PulseDecompTomlLoc, nQubits); + OQDDatabaseManager dataManager(DeviceTomlLoc, QubitTomlLoc, Gate2PulseDecompTomlLoc, + nQubits); if (LoadIon) { // FIXME(?): we only load Yb171 ion since the hardware ion species is unlikely to change @@ -114,7 +115,9 @@ struct QuantumToIonPass : impl::QuantumToIonPassBase { for (const Phonon &phonon : dataManager.getPhononParams()) { phonons.push_back(cast(getPhononAttr(ctx, builder, phonon))); } - builder.create(op->getLoc(), builder.getArrayAttr(phonons)); + // TODO: For now, we only print one phonon to be consistent with TriCal examples, + // but we should print all of them eventually + builder.create(op->getLoc(), builder.getArrayAttr(phonons[0])); } RewritePatternSet ionPatterns(&getContext()); From b7101850f2a30370636500fda53ffe6c37dd4e78 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:24:35 -0500 Subject: [PATCH 41/61] normalize the angle to avoid negative time in pulses --- mlir/include/Ion/Transforms/Passes.td | 5 ++- .../Ion/Transforms/QuantumToIonPatterns.cpp | 42 ++++++++++++++++++- mlir/lib/Ion/Transforms/ion-to-llvm.cpp | 2 + 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/mlir/include/Ion/Transforms/Passes.td b/mlir/include/Ion/Transforms/Passes.td index 1de880ff4e..71acb336da 100644 --- a/mlir/include/Ion/Transforms/Passes.td +++ b/mlir/include/Ion/Transforms/Passes.td @@ -37,7 +37,8 @@ def QuantumToIonPass : Pass<"quantum-to-ion"> { let dependentDialects = [ "quantum::QuantumDialect", - "ion::IonDialect" + "ion::IonDialect", + "scf::SCFDialect" ]; let constructor = "catalyst::createQuantumToIonPass()"; @@ -49,7 +50,7 @@ def IonConversionPass : Pass<"convert-ion-to-llvm"> { let dependentDialects = [ "mlir::func::FuncDialect", "mlir::LLVM::LLVMDialect", - "catalyst::quantum::QuantumDialect" + "catalyst::quantum::QuantumDialect", ]; let constructor = "catalyst::createIonConversionPass()"; diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index fc0012251e..24968ad47b 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -18,6 +18,7 @@ #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/IR/Value.h" #include "mlir/Transforms/DialectConversion.h" @@ -132,6 +133,44 @@ int64_t getTwoQubitCombinationIndex(int64_t nQubits, int64_t idx1, int64_t idx2) return (idx1 * nQubits) - (idx1 * (idx1 + 1) / 2) + (idx2 - idx1 - 1); } +mlir::Value CreateNormalizAngle(mlir::PatternRewriter &rewriter, mlir::Location loc, + mlir::Value angle) +{ + + constexpr double PI = llvm::numbers::pi; + constexpr double FOUR_PI = 4.0 * PI; + + auto four_pi_attr = rewriter.getF64FloatAttr(FOUR_PI); + auto four_pi_const = rewriter.create(loc, angle.getType(), four_pi_attr); + + // Find angle fmod 4pi. + mlir::Value remainder = + rewriter.create(loc, angle.getType(), angle, four_pi_const); + + // Find if the remainder is less than 0. + auto zero_attr = rewriter.getZeroAttr(angle.getType()); + auto zero_const = rewriter.create(loc, angle.getType(), zero_attr); + auto less_than_zero = rewriter.create(loc, arith::CmpFPredicate::OLT, remainder, + zero_const); // Signed less than + + // Create a conditional add (if remainder < 0, add 4*PI) + auto normalized_angle = + rewriter + .create( + loc, less_than_zero, + [&](OpBuilder &builder, Location loc) { // then + mlir::Value add_op = rewriter.create( + loc, angle.getType(), remainder, four_pi_const); // or AddIOp for integers + builder.create(loc, add_op); + }, + [&](OpBuilder &builder, Location loc) { // else + builder.create(loc, remainder); + }) + .getResult(0); + + return normalized_angle; +} + /** * @brief Computes the pulse duration given the rotation angle and the Rabi frequency. * @@ -151,9 +190,10 @@ int64_t getTwoQubitCombinationIndex(int64_t nQubits, int64_t idx1, int64_t idx2) mlir::Value computePulseDuration(mlir::PatternRewriter &rewriter, mlir::Location &loc, const mlir::Value &angle, double rabi) { + auto normalizedAngle = CreateNormalizAngle(rewriter, loc, angle); TypedAttr rabiAttr = rewriter.getF64FloatAttr(rabi); mlir::Value rabiValue = rewriter.create(loc, rabiAttr).getResult(); - return rewriter.create(loc, angle, rabiValue).getResult(); + return rewriter.create(loc, normalizedAngle, rabiValue).getResult(); } mlir::LogicalResult oneQubitGateToPulse(CustomOp op, mlir::PatternRewriter &rewriter, double phase1, diff --git a/mlir/lib/Ion/Transforms/ion-to-llvm.cpp b/mlir/lib/Ion/Transforms/ion-to-llvm.cpp index a5daca7b30..b8a79b2c12 100644 --- a/mlir/lib/Ion/Transforms/ion-to-llvm.cpp +++ b/mlir/lib/Ion/Transforms/ion-to-llvm.cpp @@ -18,6 +18,7 @@ #include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" @@ -64,6 +65,7 @@ struct IonConversionPass : impl::IonConversionPassBase { target.addLegalDialect(); target.addLegalDialect(); target.addLegalDialect(); + target.addLegalDialect(); if (failed(applyPartialConversion(getOperation(), target, std::move(patterns)))) { signalPassFailure(); From f8e1c3d61270d1d7a9566d89fa425a5a9ce30406 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:24:46 -0500 Subject: [PATCH 42/61] make format --- mlir/include/Ion/Transforms/oqd_database_managers.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index 47b672be64..581ba73242 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -107,7 +107,7 @@ class OQDDatabaseManager { } void loadPhononParams(size_t n_qubits) - { + { std::string phonon_str = "phonons" + std::to_string(n_qubits); toml::node_view phononsToml = sourceTomlGateDecomposition[phonon_str]; size_t numPhonons = phononsToml.as_array()->size(); @@ -160,7 +160,8 @@ class OQDDatabaseManager { std::set levelEncodings{"downstate", "upstate", "estate", "estate2"}; assert((levelEncodings.count(level1) & levelEncodings.count(level2)) && - "Only \"downstate\", \"upstate\", \"estate\" and \"estate2\" are allowed in the atom's " + "Only \"downstate\", \"upstate\", \"estate\" and \"estate2\" are allowed in the " + "atom's " "transition levels."); return Transition(level1, level2, multipole, einstein_a); From beda7b7d56908e80a5a8156f237222047c94998b Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:24:54 -0500 Subject: [PATCH 43/61] modify test --- mlir/test/Ion/QuantumToIon.mlir | 143 ++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 35 deletions(-) diff --git a/mlir/test/Ion/QuantumToIon.mlir b/mlir/test/Ion/QuantumToIon.mlir index e1d85c6732..32c1ef12b3 100644 --- a/mlir/test/Ion/QuantumToIon.mlir +++ b/mlir/test/Ion/QuantumToIon.mlir @@ -61,6 +61,17 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: spin_orbital_nuclear = 4.500000e+00 // CHECK-SAME: spin_orbital_nuclear_magnetization = -5.000000e+00 // CHECK-SAME: energy = 8.115200e+14 + // CHECK-SAME: >, + // CHECK-SAME: #ion.level< + // CHECK-SAME: label = "estate2", + // CHECK-SAME: principal = 5 + // CHECK-SAME: spin = 5.000000e-01 + // CHECK-SAME: orbital = 1.000000e+00 + // CHECK-SAME: nuclear = 5.000000e-01 + // CHECK-SAME: spin_orbital = 5.000000e-01 + // CHECK-SAME: spin_orbital_nuclear = 1.000000e+00 + // CHECK-SAME: spin_orbital_nuclear_magnetization = 1.000000e+00 + // CHECK-SAME: energy = 1256.6369999999999 // CHECK-SAME: > // CHECK-SAME: ], // CHECK-SAME: mass = 1.710000e+02 @@ -93,17 +104,9 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: #ion.phonon< // CHECK-SAME: energy = 1.100000e+00 : f64, // CHECK-SAME: eigenvector = [1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00] - // CHECK-SAME: >, - // CHECK-SAME: #ion.phonon< - // CHECK-SAME: energy = 2.200000e+00 : f64, - // CHECK-SAME: eigenvector = [0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00] - // CHECK-SAME: >, - // CHECK-SAME: #ion.phonon< - // CHECK-SAME: energy = 3.300000e+00 : f64, - // CHECK-SAME: eigenvector = [0.000000e+00, 0.000000e+00, 1.000000e+00, 0.000000e+00, 0.000000e+00, 1.000000e+00] // CHECK-SAME: > // CHECK-SAME: ] - // CHECK-SAME: } + // CHECK-SAME: } %1 = quantum.alloc( 2) : !quantum.reg @@ -114,8 +117,18 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK: [[rx1out:%.+]] = ion.parallelprotocol([[qubit0]]) : !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 - // CHECK-NEXT: [[timerx1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 + // CHECK-NEXT: [[timerx1:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi1]] : f64 // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -126,7 +139,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timerx1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, // CHECK-SAME: polarization = [0, 1, 2], @@ -138,8 +151,18 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK: [[ry1out:%.+]] = ion.parallelprotocol([[rx1out]]) : !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 - // CHECK-NEXT: [[timery1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 + // CHECK-NEXT: [[timery1:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi1]] : f64 // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -150,7 +173,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timery1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, // CHECK-SAME: polarization = [0, 1, 2], @@ -162,8 +185,18 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK: [[rx2out:%.+]] = ion.parallelprotocol([[ry1out]]) : !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.100000e+00 : f64 - // CHECK-NEXT: [[timerx2:%.+]] = arith.divf %arg0, [[rabi1]] : f64 + // CHECK-NEXT: [[timerx2:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi1]] : f64 // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -174,7 +207,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timerx2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.100000e+00 : f64, // CHECK-SAME: detuning = 2.200000e+00 : f64, // CHECK-SAME: polarization = [0, 1, 2], @@ -186,8 +219,18 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK: [[msout:%.+]] = ion.parallelprotocol([[rx2out]], [[qubit1]]) : !quantum.bit, !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 1.230000e+00 : f64 - // CHECK-NEXT: [[timems:%.+]] = arith.divf %arg0, [[rabi2]] : f64 + // CHECK-NEXT: [[timems:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi2]] : f64 // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -198,7 +241,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 5.660000e+00 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -206,7 +249,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 3.4{{.*}} : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -222,7 +265,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 8.960000e+00 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -230,7 +273,7 @@ func.func @example_ion_two_qubit(%arg0: f64) -> !quantum.bit attributes {qnode} // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 0.1{{.*}} : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -263,8 +306,18 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK: [[ms1out:%.+]]:2 = ion.parallelprotocol([[qubit0]], [[qubit1]]) : !quantum.bit, !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi1:%.+]] = arith.constant 1.230000e+00 : f64 - // CHECK-NEXT: [[timems1:%.+]] = arith.divf %arg0, [[rabi1]] : f64 + // CHECK-NEXT: [[timems1:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi1]] : f64 // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -275,7 +328,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 5.660000e+00 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -283,7 +336,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 3.4599999999999995 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -299,7 +352,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 8.960000e+00 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -307,7 +360,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems1]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 1.230000e+00 : f64, // CHECK-SAME: detuning = 0.15999999999999925 : f64, // CHECK-SAME: polarization = [7, 8, 9], @@ -319,8 +372,18 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK: [[ms2out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#0, [[qubit2]]) : !quantum.bit, !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi2:%.+]] = arith.constant 4.560000e+00 : f64 - // CHECK-NEXT: [[timems2:%.+]] = arith.divf %arg0, [[rabi2]] : f64 + // CHECK-NEXT: [[timems2:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi2]] : f64 // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -331,7 +394,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 8.990000e+00 : f64, // CHECK-SAME: polarization = [1, 2, 3], @@ -339,7 +402,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 6.7899999999999991 : f64, // CHECK-SAME: polarization = [1, 2, 3], @@ -355,7 +418,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 1.559000e+01 : f64, // CHECK-SAME: polarization = [1, 2, 3], @@ -363,7 +426,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} // CHECK-NEXT: ion.pulse([[timems2]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 4.560000e+00 : f64, // CHECK-SAME: detuning = 0.1899999999999995 : f64, // CHECK-SAME: polarization = [1, 2, 3], @@ -375,8 +438,18 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK: [[ms3out:%.+]]:2 = ion.parallelprotocol([[ms1out]]#1, [[ms2out]]#1) : !quantum.bit, !quantum.bit { // CHECK-NEXT: ^{{.*}}(%arg1: !quantum.bit, %arg2: !quantum.bit): + // CHECK-NEXT:%cst = arith.constant 12.566370614359172 : f64 + // CHECK-NEXT: [[remainder:%.+]] = arith.remf %arg0, %cst : f64 + // CHECK-NEXT: %cst_0 = arith.constant 0.000000e+00 : f64 + // CHECK-NEXT: [[negative:%.+]] = arith.cmpf olt, [[remainder:%.+]], %cst_0 : f64 + // CHECK-NEXT: [[normalized_angle:%.+]] = scf.if [[negative:%.+]] -> (f64) { + // CHECK-NEXT: [[adjusted:%.+]] = arith.addf [[remainder:%.+]], %cst : f64 + // CHECK-NEXT: scf.yield [[adjusted:%.+]] : f64 + // CHECK-NEXT: } else { + // CHECK-NEXT: scf.yield [[remainder:%.+]] : f64 + // CHECK-NEXT: } // CHECK-NEXT: [[rabi3:%.+]] = arith.constant 99.989999999999994 : f64 - // CHECK-NEXT: [[timems3:%.+]] = arith.divf %arg0, [[rabi3]] : f64 + // CHECK-NEXT: [[timems3:%.+]] = arith.divf [[normalized_angle:%.+]], [[rabi3]] : f64 // CHECK-NEXT: [[p1:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< // CHECK-SAME: transition_index = 0 : i64, @@ -387,7 +460,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p2:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.045000e+02 : f64, // CHECK-SAME: polarization = [37, 42, 43], @@ -395,7 +468,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p3:%.+]] = ion.pulse([[timems3]] : f64) %arg1 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 95.699999999999989 : f64, // CHECK-SAME: polarization = [37, 42, 43], @@ -411,7 +484,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p5:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 1.078000e+02 : f64, // CHECK-SAME: polarization = [37, 42, 43], @@ -419,7 +492,7 @@ func.func @example_ion_three_qubit(%arg0: f64) -> (!quantum.bit, !quantum.bit, ! // CHECK-SAME: phase = 0.000000e+00 : f64} : !ion.pulse // CHECK-NEXT: [[p6:%.+]] = ion.pulse([[timems3]] : f64) %arg2 { // CHECK-SAME: beam = #ion.beam< - // CHECK-SAME: transition_index = 1 : i64, + // CHECK-SAME: transition_index = 2 : i64, // CHECK-SAME: rabi = 99.989999999999994 : f64, // CHECK-SAME: detuning = 92.399999999999991 : f64, // CHECK-SAME: polarization = [37, 42, 43], From bce1d1c9b1685f4588e06fbba6513364d2eb909f Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Wed, 19 Feb 2025 20:39:39 -0500 Subject: [PATCH 44/61] remove empty line --- mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index 24968ad47b..c65cbbfcf5 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -136,7 +136,6 @@ int64_t getTwoQubitCombinationIndex(int64_t nQubits, int64_t idx1, int64_t idx2) mlir::Value CreateNormalizAngle(mlir::PatternRewriter &rewriter, mlir::Location loc, mlir::Value angle) { - constexpr double PI = llvm::numbers::pi; constexpr double FOUR_PI = 4.0 * PI; From dffca794e81e635b71771db9a68318bd378e5cb5 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 09:56:22 -0500 Subject: [PATCH 45/61] test coverage --- runtime/tests/Test_OQDDevice.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index a2fe7e38e4..1e1f0794c1 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -93,8 +93,18 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") "modes":[ { "class_": "Phonon", - "eigenvector": [0.0,0.0,1.0], + "eigenvector": [1.0,0.0,0.0], "energy": 3.3 + }, + { + "class_": "Phonon", + "eigenvector": [0.0,1.0,0.0], + "energy": 4.4 + }, + { + "class_": "Phonon", + "eigenvector": [0.0,0.0,1.0], + "energy": 5.5 } ], "ions": [ @@ -893,8 +903,18 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") }PHONON: { "class_": "Phonon", - "eigenvector": [0.0,0.0,1.0], + "eigenvector": [1.0,0.0,0.0], "energy": 3.3 + }PHONON: + { + "class_": "Phonon", + "eigenvector": [0.0,1.0,0.0], + "energy": 4.4 + }PHONON: + { + "class_": "Phonon", + "eigenvector": [0.0,0.0,1.0], + "energy": 4.4 })"}; size_t num_qubits = 2; From 8eca0d439ebec1156f165ff290828497188d5ed8 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 09:56:33 -0500 Subject: [PATCH 46/61] revert mistaken change --- runtime/lib/backend/oqd/OQDDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index 8f0a68e2b7..26564ea1e3 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -81,7 +81,7 @@ void OQDDevice::NamedOperation(const std::string &name, const std::vector &eigvals, DataView &counts, const std::vector &wires, size_t shots) { - return; + RT_FAIL("Unsupported functionality"); } void OQDDevice::PrintState() { RT_FAIL("Unsupported functionality"); } From 53379bc4b9b51f431b48e4c7932b119bf03f38ec Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 09:56:55 -0500 Subject: [PATCH 47/61] remove keep_intermediate in test --- frontend/test/test_oqd/oqd/test_openapl_generation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index 685f08b50c..9da91a0863 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -91,7 +91,7 @@ def test_CNOT_gate(self): """Test OpenAPL generation for a circuit with a single CNOT circuit.""" oqd_dev = OQDDevice(backend="default", shots=4, wires=2) - @qjit(pipelines=self.oqd_pipelines, keep_intermediate=True) + @qjit(pipelines=self.oqd_pipelines) @qml.qnode(oqd_dev) def circuit(x): qml.CNOT(wires=[0, 1]) From 6cfdfea3f0fb389e35c524ea9a0252b87a103336 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 10:28:23 -0500 Subject: [PATCH 48/61] Code factor --- .../test_oqd/oqd/test_openapl_generation.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index 9da91a0863..cead8687f7 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -60,9 +60,7 @@ class TestOpenAPL: ), ] - device_toml = "device.toml " - qubit_toml = "qubit.toml " - gate_toml = "gate.toml" + output_f = "/Users/mehrdad.malek/catalyst/__openapl__output.json" def test_RX_gate(self): """Test OpenAPL generation for a circuit with a single RX Gate.""" @@ -76,16 +74,19 @@ def circuit(x): circuit(1.5708) - with open("/Users/mehrdad.malek/catalyst/__openapl__output.json", "r") as f: + expected_f = "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_RX.json" + with open(self.output_f, "r", encoding="utf-8") as f: catalyst_json = json.load(f) with open( - "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_RX.json", "r" + expected_f, + "r", + encoding="utf-8", ) as f: expected_json = json.load(f) assert sorted(catalyst_json.items()) == sorted(expected_json.items()) - os.remove("/Users/mehrdad.malek/catalyst/__openapl__output.json") + os.remove(self.output_f) def test_CNOT_gate(self): """Test OpenAPL generation for a circuit with a single CNOT circuit.""" @@ -99,12 +100,13 @@ def circuit(x): circuit(1.5708) - with open("/Users/mehrdad.malek/catalyst/__openapl__output.json", "r") as f: + with open(self.output_f, "r", encoding="utf-8") as f: catalyst_json = json.load(f) - with open( - "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_CNOT.json", "r" - ) as f: + expected_f = ( + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_CNOT.json" + ) + with open(expected_f, "r", encoding="utf-8") as f: expected_json = json.load(f) assert sorted(catalyst_json.items()) == sorted(expected_json.items()) From 57446068928dbbc097456a761da9b8831fb902e5 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 10:43:34 -0500 Subject: [PATCH 49/61] Fix paths --- .../test/test_oqd/oqd/test_openapl_generation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index cead8687f7..557db15e6c 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -43,11 +43,11 @@ class TestOpenAPL: "func.func(ions-decomposition)", "func.func(quantum-to-ion{" + "device-toml-loc=" - + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/device.toml " + + "frontend/test/test_oqd/oqd/calibration_data/device.toml " + "qubit-toml-loc=" - + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/qubit.toml " + + "frontend/test/test_oqd/oqd/calibration_data/qubit.toml " + "gate-to-pulse-toml-loc=" - + "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/calibration_data/gate.toml" + + "frontend/test/test_oqd/oqd/calibration_data/gate.toml" + "})", "convert-ion-to-llvm", ], @@ -60,7 +60,7 @@ class TestOpenAPL: ), ] - output_f = "/Users/mehrdad.malek/catalyst/__openapl__output.json" + output_f = "__openapl__output.json" def test_RX_gate(self): """Test OpenAPL generation for a circuit with a single RX Gate.""" @@ -74,7 +74,7 @@ def circuit(x): circuit(1.5708) - expected_f = "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_RX.json" + expected_f = "frontend/test/test_oqd/oqd/test_single_RX.json" with open(self.output_f, "r", encoding="utf-8") as f: catalyst_json = json.load(f) @@ -104,13 +104,13 @@ def circuit(x): catalyst_json = json.load(f) expected_f = ( - "/Users/mehrdad.malek/catalyst/frontend/test/test_oqd/oqd/test_single_CNOT.json" + "frontend/test/test_oqd/oqd/test_single_CNOT.json" ) with open(expected_f, "r", encoding="utf-8") as f: expected_json = json.load(f) assert sorted(catalyst_json.items()) == sorted(expected_json.items()) - os.remove("/Users/mehrdad.malek/catalyst/__openapl__output.json") + os.remove("__openapl__output.json") if __name__ == "__main__": From d4764244d55aad5b44f19e614fb3bf48b3a7ae85 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 10:44:02 -0500 Subject: [PATCH 50/61] we have to support PartialCounts for tests to pass. return for now --- runtime/lib/backend/oqd/OQDDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/lib/backend/oqd/OQDDevice.cpp b/runtime/lib/backend/oqd/OQDDevice.cpp index 26564ea1e3..8f0a68e2b7 100644 --- a/runtime/lib/backend/oqd/OQDDevice.cpp +++ b/runtime/lib/backend/oqd/OQDDevice.cpp @@ -81,7 +81,7 @@ void OQDDevice::NamedOperation(const std::string &name, const std::vector &eigvals, DataView &counts, const std::vector &wires, size_t shots) { - RT_FAIL("Unsupported functionality"); + return; } void OQDDevice::PrintState() { RT_FAIL("Unsupported functionality"); } From e031c64c7ed344069cd873fcb6a377653771fbec Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 10:48:49 -0500 Subject: [PATCH 51/61] remove unsued parameter --- frontend/test/test_oqd/oqd/test_openapl_generation.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index 557db15e6c..17e21daeef 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -94,18 +94,16 @@ def test_CNOT_gate(self): @qjit(pipelines=self.oqd_pipelines) @qml.qnode(oqd_dev) - def circuit(x): + def circuit(): qml.CNOT(wires=[0, 1]) return qml.counts() - circuit(1.5708) + circuit() with open(self.output_f, "r", encoding="utf-8") as f: catalyst_json = json.load(f) - expected_f = ( - "frontend/test/test_oqd/oqd/test_single_CNOT.json" - ) + expected_f = "frontend/test/test_oqd/oqd/test_single_CNOT.json" with open(expected_f, "r", encoding="utf-8") as f: expected_json = json.load(f) From 1896bd66800e9fd740fb170a44f384f67f4f35e8 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 10:51:21 -0500 Subject: [PATCH 52/61] Fix test --- runtime/tests/Test_OQDDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/tests/Test_OQDDevice.cpp b/runtime/tests/Test_OQDDevice.cpp index 1e1f0794c1..2fb67f48d1 100644 --- a/runtime/tests/Test_OQDDevice.cpp +++ b/runtime/tests/Test_OQDDevice.cpp @@ -914,7 +914,7 @@ TEST_CASE("Test OpenAPL Program generation", "[oqd]") { "class_": "Phonon", "eigenvector": [0.0,0.0,1.0], - "energy": 4.4 + "energy": 5.5 })"}; size_t num_qubits = 2; From daf4575b1a1d2c45e5faa8b490fdbf318c83b0c6 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 14:38:58 -0500 Subject: [PATCH 53/61] use recursion for collecting phonon tokens --- runtime/lib/backend/oqd/OQDDevice.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index f3a1cf968e..bab7b0ae57 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -58,6 +58,16 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { return res; } + void collectPhonons(const std::string &source, const std::string &token, + std::vector &phonon_specs) + { + std::string::size_type lpos = source.rfind(token); + if (lpos != std::string::npos) { + collectPhonons(source.substr(0, lpos), token, phonon_specs); + phonon_specs.push_back(source.substr(lpos + token.length())); + } + } + public: explicit OQDDevice(const std::string &kwargs = "{device_type : oqd, backend : default}") { @@ -79,13 +89,7 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { } phonon_specs.clear(); - size_t phonon_token_pos = kwargs.find(phonon_token); - while (phonon_token_pos != std::string::npos) { - size_t phonon_start_pos = phonon_token_pos + phonon_token.length(); - phonon_token_pos = kwargs.find(phonon_token, phonon_start_pos); - phonon_specs.push_back( - kwargs.substr(phonon_start_pos, phonon_token_pos - phonon_start_pos)); - } + collectPhonons(kwargs, phonon_token, phonon_specs); device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs.substr(0, ion_token_pos)); device_shots = device_kwargs.contains("shots") From 53c92a1f963fb361ffd28ff5bf1370c92a8aab65 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 14:40:39 -0500 Subject: [PATCH 54/61] Add EOF newline --- frontend/test/test_oqd/oqd/test_single_CNOT.json | 2 +- frontend/test/test_oqd/oqd/test_single_RX.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_single_CNOT.json b/frontend/test/test_oqd/oqd/test_single_CNOT.json index 2b6a39bae4..b9adbd0a0b 100644 --- a/frontend/test/test_oqd/oqd/test_single_CNOT.json +++ b/frontend/test/test_oqd/oqd/test_single_CNOT.json @@ -1253,4 +1253,4 @@ } ] } -} \ No newline at end of file +} diff --git a/frontend/test/test_oqd/oqd/test_single_RX.json b/frontend/test/test_oqd/oqd/test_single_RX.json index c2d1cb9c27..1236603b39 100644 --- a/frontend/test/test_oqd/oqd/test_single_RX.json +++ b/frontend/test/test_oqd/oqd/test_single_RX.json @@ -328,4 +328,4 @@ } ] } -} \ No newline at end of file +} From 1b16c5041bf38616d422d008a10333ba87a38669 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 14:41:34 -0500 Subject: [PATCH 55/61] Fix typos --- frontend/test/test_oqd/oqd/test_openapl_generation.py | 2 +- mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index 17e21daeef..124a5d5584 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -29,7 +29,7 @@ class TestOpenAPL: oqd_pipelines = [ ( - "device-agnoistic-pipeline", + "device-agnostic-pipeline", [ "enforce-runtime-invariants-pipeline", "hlo-lowering-pipeline", diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index c65cbbfcf5..ee72523299 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -133,7 +133,7 @@ int64_t getTwoQubitCombinationIndex(int64_t nQubits, int64_t idx1, int64_t idx2) return (idx1 * nQubits) - (idx1 * (idx1 + 1) / 2) + (idx2 - idx1 - 1); } -mlir::Value CreateNormalizAngle(mlir::PatternRewriter &rewriter, mlir::Location loc, +mlir::Value CreateNormalizedAngle(mlir::PatternRewriter &rewriter, mlir::Location loc, mlir::Value angle) { constexpr double PI = llvm::numbers::pi; @@ -189,7 +189,7 @@ mlir::Value CreateNormalizAngle(mlir::PatternRewriter &rewriter, mlir::Location mlir::Value computePulseDuration(mlir::PatternRewriter &rewriter, mlir::Location &loc, const mlir::Value &angle, double rabi) { - auto normalizedAngle = CreateNormalizAngle(rewriter, loc, angle); + auto normalizedAngle = CreateNormalizedAngle(rewriter, loc, angle); TypedAttr rabiAttr = rewriter.getF64FloatAttr(rabi); mlir::Value rabiValue = rewriter.create(loc, rabiAttr).getResult(); return rewriter.create(loc, normalizedAngle, rabiValue).getResult(); From 44c4f22d6ccdee7ce41385ea2d30caf6c7712c88 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 14:48:21 -0500 Subject: [PATCH 56/61] Address minor comments --- mlir/include/Ion/Transforms/oqd_database_managers.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index 581ba73242..51752b6de5 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -107,12 +107,15 @@ class OQDDatabaseManager { } void loadPhononParams(size_t n_qubits) - { + { + // TODO: The fact that loading phonons depend on the number of qubits is a bit of a hack. + // This is not ideal since we want to support dynamic number of qubits in the future. + // We should find a better way to handle this in the database. std::string phonon_str = "phonons" + std::to_string(n_qubits); toml::node_view phononsToml = sourceTomlGateDecomposition[phonon_str]; size_t numPhonons = phononsToml.as_array()->size(); - auto parseSingleDirection = [](auto direction) { + auto parseSinglePhonon = [](auto direction) { double energy = direction["energy"].as_floating_point()->get(); std::vector eigenvector = tomlArray2StdVector(*(direction["eigenvector"].as_array())); @@ -120,7 +123,7 @@ class OQDDatabaseManager { }; for (size_t i = 0; i < numPhonons; i++) { - Phonon phonon = parseSingleDirection(phononsToml[i]); + Phonon phonon = parseSinglePhonon(phononsToml[i]); phonons.push_back(phonon); } } From 5d0ab28fbe8ef22e4a0f23798351248b5eb1adae Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 14:50:29 -0500 Subject: [PATCH 57/61] make format --- mlir/include/Ion/Transforms/oqd_database_managers.hpp | 2 +- mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mlir/include/Ion/Transforms/oqd_database_managers.hpp b/mlir/include/Ion/Transforms/oqd_database_managers.hpp index 51752b6de5..20c89459b7 100644 --- a/mlir/include/Ion/Transforms/oqd_database_managers.hpp +++ b/mlir/include/Ion/Transforms/oqd_database_managers.hpp @@ -107,7 +107,7 @@ class OQDDatabaseManager { } void loadPhononParams(size_t n_qubits) - { + { // TODO: The fact that loading phonons depend on the number of qubits is a bit of a hack. // This is not ideal since we want to support dynamic number of qubits in the future. // We should find a better way to handle this in the database. diff --git a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp index ee72523299..618035f908 100644 --- a/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp +++ b/mlir/lib/Ion/Transforms/QuantumToIonPatterns.cpp @@ -134,7 +134,7 @@ int64_t getTwoQubitCombinationIndex(int64_t nQubits, int64_t idx1, int64_t idx2) } mlir::Value CreateNormalizedAngle(mlir::PatternRewriter &rewriter, mlir::Location loc, - mlir::Value angle) + mlir::Value angle) { constexpr double PI = llvm::numbers::pi; constexpr double FOUR_PI = 4.0 * PI; From a42326d271e97694f283b44412f73fb974c9b5f0 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 15:29:30 -0500 Subject: [PATCH 58/61] proper path management for toml files --- .../test/test_oqd/oqd/test_openapl_generation.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index 124a5d5584..f3aa71a432 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -26,7 +26,7 @@ class TestOpenAPL: """Test that the OQD device correctly generates an OpenAPL program.""" - + toml_path = os.path.join(os.path.dirname(__file__), "calibration_data/") oqd_pipelines = [ ( "device-agnostic-pipeline", @@ -42,12 +42,9 @@ class TestOpenAPL: [ "func.func(ions-decomposition)", "func.func(quantum-to-ion{" - + "device-toml-loc=" - + "frontend/test/test_oqd/oqd/calibration_data/device.toml " - + "qubit-toml-loc=" - + "frontend/test/test_oqd/oqd/calibration_data/qubit.toml " - + "gate-to-pulse-toml-loc=" - + "frontend/test/test_oqd/oqd/calibration_data/gate.toml" + + "device-toml-loc=" + toml_path + "device.toml " + + "qubit-toml-loc=" + toml_path + "qubit.toml " + + "gate-to-pulse-toml-loc=" + toml_path + "gate.toml" + "})", "convert-ion-to-llvm", ], @@ -65,7 +62,6 @@ class TestOpenAPL: def test_RX_gate(self): """Test OpenAPL generation for a circuit with a single RX Gate.""" oqd_dev = OQDDevice(backend="default", shots=4, wires=1) - @qjit(pipelines=self.oqd_pipelines) @qml.qnode(oqd_dev) def circuit(x): From 6e64474ec397407f1c52fe01a26ef63696db0d24 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 15:33:10 -0500 Subject: [PATCH 59/61] make format --- .../test/test_oqd/oqd/test_openapl_generation.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/test/test_oqd/oqd/test_openapl_generation.py b/frontend/test/test_oqd/oqd/test_openapl_generation.py index f3aa71a432..25f0857fa5 100644 --- a/frontend/test/test_oqd/oqd/test_openapl_generation.py +++ b/frontend/test/test_oqd/oqd/test_openapl_generation.py @@ -26,6 +26,7 @@ class TestOpenAPL: """Test that the OQD device correctly generates an OpenAPL program.""" + toml_path = os.path.join(os.path.dirname(__file__), "calibration_data/") oqd_pipelines = [ ( @@ -42,9 +43,15 @@ class TestOpenAPL: [ "func.func(ions-decomposition)", "func.func(quantum-to-ion{" - + "device-toml-loc=" + toml_path + "device.toml " - + "qubit-toml-loc=" + toml_path + "qubit.toml " - + "gate-to-pulse-toml-loc=" + toml_path + "gate.toml" + + "device-toml-loc=" + + toml_path + + "device.toml " + + "qubit-toml-loc=" + + toml_path + + "qubit.toml " + + "gate-to-pulse-toml-loc=" + + toml_path + + "gate.toml" + "})", "convert-ion-to-llvm", ], @@ -62,6 +69,7 @@ class TestOpenAPL: def test_RX_gate(self): """Test OpenAPL generation for a circuit with a single RX Gate.""" oqd_dev = OQDDevice(backend="default", shots=4, wires=1) + @qjit(pipelines=self.oqd_pipelines) @qml.qnode(oqd_dev) def circuit(x): From 76f70ec9778d846d89e460b54e4c656b928fb853 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 16:57:11 -0500 Subject: [PATCH 60/61] revert recursion --- runtime/lib/backend/oqd/OQDDevice.hpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/runtime/lib/backend/oqd/OQDDevice.hpp b/runtime/lib/backend/oqd/OQDDevice.hpp index bab7b0ae57..f3a1cf968e 100644 --- a/runtime/lib/backend/oqd/OQDDevice.hpp +++ b/runtime/lib/backend/oqd/OQDDevice.hpp @@ -58,16 +58,6 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { return res; } - void collectPhonons(const std::string &source, const std::string &token, - std::vector &phonon_specs) - { - std::string::size_type lpos = source.rfind(token); - if (lpos != std::string::npos) { - collectPhonons(source.substr(0, lpos), token, phonon_specs); - phonon_specs.push_back(source.substr(lpos + token.length())); - } - } - public: explicit OQDDevice(const std::string &kwargs = "{device_type : oqd, backend : default}") { @@ -89,7 +79,13 @@ class OQDDevice final : public Catalyst::Runtime::QuantumDevice { } phonon_specs.clear(); - collectPhonons(kwargs, phonon_token, phonon_specs); + size_t phonon_token_pos = kwargs.find(phonon_token); + while (phonon_token_pos != std::string::npos) { + size_t phonon_start_pos = phonon_token_pos + phonon_token.length(); + phonon_token_pos = kwargs.find(phonon_token, phonon_start_pos); + phonon_specs.push_back( + kwargs.substr(phonon_start_pos, phonon_token_pos - phonon_start_pos)); + } device_kwargs = Catalyst::Runtime::parse_kwargs(kwargs.substr(0, ion_token_pos)); device_shots = device_kwargs.contains("shots") From 80fbddc1ae226cbe42c72ac89cfd53642573c7d5 Mon Sep 17 00:00:00 2001 From: Mehrdad Malekmohammadi Date: Thu, 20 Feb 2025 16:58:58 -0500 Subject: [PATCH 61/61] remove unnecessary initialization json fields --- mlir/lib/Ion/Transforms/ConversionPatterns.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp index 3e2a8cc475..68949da008 100644 --- a/mlir/lib/Ion/Transforms/ConversionPatterns.cpp +++ b/mlir/lib/Ion/Transforms/ConversionPatterns.cpp @@ -201,7 +201,6 @@ struct ModesOpPattern : public OpConversionPattern { json phonon_json = R"({ "class_": "Phonon", - "energy": [], "eigenvector" : [] })"_json; phonon_json["energy"] = phononAttr.getEnergy().getValue().convertToDouble();