Loading cmake/qcor_config.hpp.in +1 −0 Original line number Diff line number Diff line Loading @@ -2,3 +2,4 @@ #define QCOR_LIB_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}" #define QCOR_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}" #define XACC_ROOT "${XACC_ROOT}" #define LLVM_ROOT "${LLVM_INSTALL_PREFIX}" examples/qpu_lambda/d2_with_htest.cpp 0 → 100644 +47 −0 Original line number Diff line number Diff line #include <qcor_hadamard_test> int main() { // Create the Deuteron Hamiltonian auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1); for (auto x : linspace(-constants::pi, constants::pi, 10)) { auto terms = H.getNonIdentitySubTerms(); double sum = H.getIdentitySubTerm()->coefficient().real(); for (auto term : terms) { auto pop = std::dynamic_pointer_cast<PauliOperator>(term); assert(pop && pop->nTerms() == 1); auto [zv, xv] = pop->toBinaryVectors(2); auto sp = qpu_lambda( [](qreg q) { X(q.head()); Ry(q.tail(), x); X::ctrl(q.tail(), q.head()); }, x); auto l = qpu_lambda( [](qreg q) { for (auto [i, x_val] : enumerate(xv)) { auto z_val = zv[i]; if (x_val == z_val && x_val == 1) { Y(q[i]); } else if (x_val == 1) { X(q[i]); } else if (z_val == 1) { Z(q[i]); } } }, xv, zv); auto val = qcor::hadamard_test(sp, l, 2); sum += pop->coefficient().real() * val; } print("E(", x, ") = ", sum); } } No newline at end of file lib/impl/hadamard_test.hpp +8 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,14 @@ double hadamard_test(StatePrep state_prep, Unitary unitary, auto q = qalloc(n_state_qubits + 1); __quantum_hadamard_test(q, state_prep, unitary); // Compute <psi|U|psi> // First make sure we have counts, // if not, grab exp-val-z key in buffer auto counts = q.counts(); if (counts.empty()) { return q.results()->getExpectationValueZ(); } // We have counts, so use that double count1 = (double)q.counts().find("1")->second; double count2 = (double)q.counts().find("0")->second; return std::fabs((count1 - count2) / (count1 + count2)); Loading mlir/dialect/include/Quantum/QuantumOps.h +1 −2 Original line number Diff line number Diff line Loading @@ -15,4 +15,3 @@ #define GET_OP_CLASSES #include "Quantum/QuantumOps.h.inc" No newline at end of file mlir/dialect/include/Quantum/QuantumOps.td +55 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ def StringType : OpaqueType<"quantum", "StringType", "opaque string type">; def QallocOp : QuantumOp<"qalloc", []> { let arguments = (ins AnyI64Attr:$size, StrAttr:$name); let results = (outs ArrayType:$qubits); let printer = [{ auto op = *this; p << "q.qalloc(" << op.size() << ") { name = " << op.name() << " }"; p << " : " << op.qubits().getType(); }]; } // Create an array holding Qubit pointers for aliasing purposes, Loading @@ -27,6 +31,9 @@ def QaliasArrayAllocOp : QuantumOp<"createQubitArray", []> { def ExtractQubitOp : QuantumOp<"qextract", []> { let arguments = (ins ArrayType:$qreg, AnyInteger:$idx); let results = (outs QubitType:$qbit); let printer = [{ auto op = *this; p << "q.extract(" << op.getOperands() << ")"; p << " : " << op.qbit().getType(); }]; } def GeneralArrayExtractOp : QuantumOp<"array_extract", []> { Loading Loading @@ -55,11 +62,17 @@ def ArrayConcatOp : QuantumOp<"qarray_concat", []> { def StartCtrlURegion : QuantumOp<"start_ctrl_u_region", []> { let arguments = (ins); let results = (outs); let printer = [{ p << "q.ctrl_region {"; }]; } def EndCtrlURegion : QuantumOp<"end_ctrl_u_region", []> { let arguments = (ins QubitType:$ctrl_qubit); let results = (outs); let printer = [{ auto op = *this; p << "} (ctrl_bit = " << op.ctrl_qubit() << ")"; }]; } def StartAdjointURegion : QuantumOp<"start_adj_u_region", []> { Loading @@ -85,36 +98,78 @@ def EndPowURegion : QuantumOp<"end_pow_u_region", []> { def InstOp : QuantumOp<"inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); let results = (outs Optional<ResultType>:$bit); let printer = [{ auto op = *this; p << "q." << op.name() << "(" << op.getOperands() << ") : " << op.getResultTypes(); }]; } def ValueSemanticsInstOp : QuantumOp<"value_inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); let results = (outs Variadic<AnyTypeOf<[ResultType, QubitType]>>:$result); let printer = [{ auto op = *this; p << "qvs." << op.name() << "(" << op.getOperands() << ") : " << op.result().getType(); }]; } def DeallocOp : QuantumOp<"dealloc", []> { let arguments = (ins ArrayType:$qubits); let results = (outs); let printer = [{ auto op = *this; p << "q.dealloc(" << op.qubits() << ")"; }]; } def QRTInitOp : QuantumOp<"init", []> { let arguments = (ins AnyI32:$argc, ArgvType:$argv); let results = (outs); let printer = [{ auto op = *this; p << "q.init(" << op.getOperands() << ")"; }]; } def QRTFinalizeOp : QuantumOp<"finalize", []> { let arguments = (ins); let results = (outs); let printer = [{ p << "q.finalize()"; }]; } def SetQregOp : QuantumOp<"set_qreg", []> { let arguments = (ins QregType:$qreg); let results = (outs); let printer = [{ auto op = *this; p << "q.set_qreg(" << op.qreg() << ")"; }]; } def PrintOp : QuantumOp<"print", []> { let arguments = (ins Variadic<AnyType>:$print_args); let results = (outs); let printer = [{ auto op = *this; p << "q.print(" << op.getOperands() << ")"; }]; } def CreateStringLiteralOp : QuantumOp<"createString", []> { let arguments = (ins StrAttr:$text, StrAttr:$varname); let results = (outs StringType:$result); let printer = [{ auto op = *this; p << "q.create_string(\"" << op.text() << "\")"; }]; } // Cast QIR Result to bool (i1 type) def ResultCastOp : QuantumOp<"resultCast", []> { let arguments = (ins ResultType:$measure_result); let results = (outs I1:$bit_result); let printer = [{ auto op = *this; p << "q.resultCast" << "(" << op.measure_result() << ") : " << op.bit_result().getType(); }]; } // Sign-Unsign cast: // Rationale: std dialect only accepts signless type (i.e. int but not uint) // we need to have this cast op in the dialect to finally lower to LLVM cast // which can handle int -> uint casting at the final lowering phase. // Note: std.index_cast cannot handle int -> unit casting (one of the type must be an index type). def IntegerCastOp : QuantumOp<"integerCast", []> { let arguments = (ins AnyInteger:$input); let results = (outs AnyInteger:$output); let printer = [{ auto op = *this; p << "q.integerCast" << "(" << op.input() << ") : " << op.output().getType(); }]; } #endif // Quantum_OPS No newline at end of file Loading
cmake/qcor_config.hpp.in +1 −0 Original line number Diff line number Diff line Loading @@ -2,3 +2,4 @@ #define QCOR_LIB_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}" #define QCOR_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}" #define XACC_ROOT "${XACC_ROOT}" #define LLVM_ROOT "${LLVM_INSTALL_PREFIX}"
examples/qpu_lambda/d2_with_htest.cpp 0 → 100644 +47 −0 Original line number Diff line number Diff line #include <qcor_hadamard_test> int main() { // Create the Deuteron Hamiltonian auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) + .21829 * Z(0) - 6.125 * Z(1); for (auto x : linspace(-constants::pi, constants::pi, 10)) { auto terms = H.getNonIdentitySubTerms(); double sum = H.getIdentitySubTerm()->coefficient().real(); for (auto term : terms) { auto pop = std::dynamic_pointer_cast<PauliOperator>(term); assert(pop && pop->nTerms() == 1); auto [zv, xv] = pop->toBinaryVectors(2); auto sp = qpu_lambda( [](qreg q) { X(q.head()); Ry(q.tail(), x); X::ctrl(q.tail(), q.head()); }, x); auto l = qpu_lambda( [](qreg q) { for (auto [i, x_val] : enumerate(xv)) { auto z_val = zv[i]; if (x_val == z_val && x_val == 1) { Y(q[i]); } else if (x_val == 1) { X(q[i]); } else if (z_val == 1) { Z(q[i]); } } }, xv, zv); auto val = qcor::hadamard_test(sp, l, 2); sum += pop->coefficient().real() * val; } print("E(", x, ") = ", sum); } } No newline at end of file
lib/impl/hadamard_test.hpp +8 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,14 @@ double hadamard_test(StatePrep state_prep, Unitary unitary, auto q = qalloc(n_state_qubits + 1); __quantum_hadamard_test(q, state_prep, unitary); // Compute <psi|U|psi> // First make sure we have counts, // if not, grab exp-val-z key in buffer auto counts = q.counts(); if (counts.empty()) { return q.results()->getExpectationValueZ(); } // We have counts, so use that double count1 = (double)q.counts().find("1")->second; double count2 = (double)q.counts().find("0")->second; return std::fabs((count1 - count2) / (count1 + count2)); Loading
mlir/dialect/include/Quantum/QuantumOps.h +1 −2 Original line number Diff line number Diff line Loading @@ -15,4 +15,3 @@ #define GET_OP_CLASSES #include "Quantum/QuantumOps.h.inc" No newline at end of file
mlir/dialect/include/Quantum/QuantumOps.td +55 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,10 @@ def StringType : OpaqueType<"quantum", "StringType", "opaque string type">; def QallocOp : QuantumOp<"qalloc", []> { let arguments = (ins AnyI64Attr:$size, StrAttr:$name); let results = (outs ArrayType:$qubits); let printer = [{ auto op = *this; p << "q.qalloc(" << op.size() << ") { name = " << op.name() << " }"; p << " : " << op.qubits().getType(); }]; } // Create an array holding Qubit pointers for aliasing purposes, Loading @@ -27,6 +31,9 @@ def QaliasArrayAllocOp : QuantumOp<"createQubitArray", []> { def ExtractQubitOp : QuantumOp<"qextract", []> { let arguments = (ins ArrayType:$qreg, AnyInteger:$idx); let results = (outs QubitType:$qbit); let printer = [{ auto op = *this; p << "q.extract(" << op.getOperands() << ")"; p << " : " << op.qbit().getType(); }]; } def GeneralArrayExtractOp : QuantumOp<"array_extract", []> { Loading Loading @@ -55,11 +62,17 @@ def ArrayConcatOp : QuantumOp<"qarray_concat", []> { def StartCtrlURegion : QuantumOp<"start_ctrl_u_region", []> { let arguments = (ins); let results = (outs); let printer = [{ p << "q.ctrl_region {"; }]; } def EndCtrlURegion : QuantumOp<"end_ctrl_u_region", []> { let arguments = (ins QubitType:$ctrl_qubit); let results = (outs); let printer = [{ auto op = *this; p << "} (ctrl_bit = " << op.ctrl_qubit() << ")"; }]; } def StartAdjointURegion : QuantumOp<"start_adj_u_region", []> { Loading @@ -85,36 +98,78 @@ def EndPowURegion : QuantumOp<"end_pow_u_region", []> { def InstOp : QuantumOp<"inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); let results = (outs Optional<ResultType>:$bit); let printer = [{ auto op = *this; p << "q." << op.name() << "(" << op.getOperands() << ") : " << op.getResultTypes(); }]; } def ValueSemanticsInstOp : QuantumOp<"value_inst", [AttrSizedOperandSegments]> { let arguments = (ins StrAttr:$name, Variadic<QubitType>:$qubits, Variadic<F64>:$params); let results = (outs Variadic<AnyTypeOf<[ResultType, QubitType]>>:$result); let printer = [{ auto op = *this; p << "qvs." << op.name() << "(" << op.getOperands() << ") : " << op.result().getType(); }]; } def DeallocOp : QuantumOp<"dealloc", []> { let arguments = (ins ArrayType:$qubits); let results = (outs); let printer = [{ auto op = *this; p << "q.dealloc(" << op.qubits() << ")"; }]; } def QRTInitOp : QuantumOp<"init", []> { let arguments = (ins AnyI32:$argc, ArgvType:$argv); let results = (outs); let printer = [{ auto op = *this; p << "q.init(" << op.getOperands() << ")"; }]; } def QRTFinalizeOp : QuantumOp<"finalize", []> { let arguments = (ins); let results = (outs); let printer = [{ p << "q.finalize()"; }]; } def SetQregOp : QuantumOp<"set_qreg", []> { let arguments = (ins QregType:$qreg); let results = (outs); let printer = [{ auto op = *this; p << "q.set_qreg(" << op.qreg() << ")"; }]; } def PrintOp : QuantumOp<"print", []> { let arguments = (ins Variadic<AnyType>:$print_args); let results = (outs); let printer = [{ auto op = *this; p << "q.print(" << op.getOperands() << ")"; }]; } def CreateStringLiteralOp : QuantumOp<"createString", []> { let arguments = (ins StrAttr:$text, StrAttr:$varname); let results = (outs StringType:$result); let printer = [{ auto op = *this; p << "q.create_string(\"" << op.text() << "\")"; }]; } // Cast QIR Result to bool (i1 type) def ResultCastOp : QuantumOp<"resultCast", []> { let arguments = (ins ResultType:$measure_result); let results = (outs I1:$bit_result); let printer = [{ auto op = *this; p << "q.resultCast" << "(" << op.measure_result() << ") : " << op.bit_result().getType(); }]; } // Sign-Unsign cast: // Rationale: std dialect only accepts signless type (i.e. int but not uint) // we need to have this cast op in the dialect to finally lower to LLVM cast // which can handle int -> uint casting at the final lowering phase. // Note: std.index_cast cannot handle int -> unit casting (one of the type must be an index type). def IntegerCastOp : QuantumOp<"integerCast", []> { let arguments = (ins AnyInteger:$input); let results = (outs AnyInteger:$output); let printer = [{ auto op = *this; p << "q.integerCast" << "(" << op.input() << ") : " << op.output().getType(); }]; } #endif // Quantum_OPS No newline at end of file