From 26fe7e7668a045663c684ea404d09666098e6f3e Mon Sep 17 00:00:00 2001 From: Bruno Schmitt Date: Mon, 7 Aug 2023 18:25:04 +0200 Subject: [PATCH] [gh] Integration tests workflow (#488) --- .github/workflows/integration_tests.yml | 74 +++++++++++++++++++ test/NVQPP/{ => integration}/bug_qubit.cpp | 25 +++++-- .../callable_kernel_arg.cpp} | 20 +++-- .../{ => integration}/graph_coloring-1.cpp | 25 +++++++ .../{ => integration}/graph_coloring.cpp | 26 +++++++ test/NVQPP/{ => integration}/if_jit.cpp | 17 ++++- .../load_value.cpp} | 11 ++- .../qspan_slices.cpp} | 18 +++-- test/NVQPP/{ => integration}/sudoku_2x2-1.cpp | 16 +++- test/NVQPP/{ => integration}/sudoku_2x2.cpp | 16 +++- .../swap_gate.cpp} | 11 +++ test/NVQPP/{ => integration}/test-int8_t.cpp | 10 +++ .../test-int8_t_free_func.cpp | 10 +++ .../variable_size_qreg.cpp} | 10 +++ 14 files changed, 258 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/integration_tests.yml rename test/NVQPP/{ => integration}/bug_qubit.cpp (73%) rename test/NVQPP/{test-0.cpp => integration/callable_kernel_arg.cpp} (79%) rename test/NVQPP/{ => integration}/graph_coloring-1.cpp (81%) rename test/NVQPP/{ => integration}/graph_coloring.cpp (83%) rename test/NVQPP/{ => integration}/if_jit.cpp (74%) rename test/NVQPP/{test-1.cpp => integration/load_value.cpp} (85%) rename test/NVQPP/{test-4.cpp => integration/qspan_slices.cpp} (78%) rename test/NVQPP/{ => integration}/sudoku_2x2-1.cpp (83%) rename test/NVQPP/{ => integration}/sudoku_2x2.cpp (82%) rename test/NVQPP/{quantinuumSwapDecomp.cpp => integration/swap_gate.cpp} (80%) rename test/NVQPP/{ => integration}/test-int8_t.cpp (81%) rename test/NVQPP/{ => integration}/test-int8_t_free_func.cpp (81%) rename test/NVQPP/{test-5.cpp => integration/variable_size_qreg.cpp} (81%) diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml new file mode 100644 index 0000000000..fa867fe24f --- /dev/null +++ b/.github/workflows/integration_tests.yml @@ -0,0 +1,74 @@ +name: Nightly integration tests + +# Run on request and every day at 3 AM UTC +on: + workflow_dispatch: + inputs: + syntax_check: + type: boolean + required: true + description: 'Run syntax checker.' + target: + description: 'Target' + required: true + default: 'none' + type: choice + options: + - none + - quantinuum + target_machine: + type: string + required: false + description: 'Target machine (e.g., H1-1E).' + schedule: + - cron: 0 3 * * * + +jobs: + integration_test: + name: Intergration test + runs-on: ubuntu-latest + environment: backend-validation + container: + image: ghcr.io/nvidia/cuda-quantum:latest-hpc + options: --user root + + steps: + - name: Get commit SHA + id: commit-sha + run: | + echo "sha=$(cat $CUDA_QUANTUM_PATH/assets/build_info.txt | grep -o 'source-sha: \S*' | cut -d ' ' -f 2)" >> $GITHUB_OUTPUT + + - name: Get code + uses: actions/checkout@v3 + with: + ref: ${{ steps.commit-sha.outputs.sha }} + fetch-depth: 1 + + - name: Setup quantinum account + if: github.event_name == 'schedule' || inputs.syntax_check || inputs.target == 'quantinuum' + run: | + curl -X POST -H "Content Type: application/json" -d '{ "email":"${{ secrets.BACKEND_LOGIN_EMAIL }}","password":"${{ secrets.QUANTINUUM_PASSWORD }}" }' https://qapi.quantinuum.com/v1/login > credentials.json + id_token=`cat credentials.json | jq -r '."id-token"'` + refresh_token=`cat credentials.json | jq -r '."refresh-token"'` + echo "key: $id_token" > ~/.quantinuum_config + echo "refresh: $refresh_token" >> ~/.quantinuum_config + + - name: QIR syntax check (Quantinuum) + if: inputs.syntax_check || github.event_name == 'schedule' + run: | + for filename in test/NVQPP/integration/*.cpp; do + [ -e "$filename" ] || echo "::error::Couldn't find files ($filename)" + nvq++ -v $filename -DSYNTAX_CHECK --target quantinuum --quantinuum-machine H1-1SC + CUDAQ_LOG_LEVEL=info ./a.out + done + shell: bash + + - name: Submit to ${{ inputs.target }} + if: inputs.target != 'none' + run: | + for filename in test/NVQPP/integration/*.cpp; do + [ -e "$filename" ] || echo "::error::Couldn't find files ($filename)" + nvq++ -v $filename --target ${{ inputs.target }} --${{ inputs.target }}-machine ${{ inputs.target_machine }} + CUDAQ_LOG_LEVEL=info ./a.out + done + shell: bash diff --git a/test/NVQPP/bug_qubit.cpp b/test/NVQPP/integration/bug_qubit.cpp similarity index 73% rename from test/NVQPP/bug_qubit.cpp rename to test/NVQPP/integration/bug_qubit.cpp index 6bc79426e2..a0445657e9 100644 --- a/test/NVQPP/bug_qubit.cpp +++ b/test/NVQPP/integration/bug_qubit.cpp @@ -11,27 +11,36 @@ // RUN: nvq++ --enable-mlir -v %s --target quantinuum --emulate -o %t.x && %t.x | FileCheck %s // RUN: cudaq-quake %s | cudaq-opt --promote-qubit-allocation | FileCheck --check-prefixes=MLIR %s -// CHECK: Test: { 0:{{[0-9]+}} 1:{{[0-9]+}} } - #include #include -struct ak2 { +struct simple_x { void operator()() __qpu__ { cudaq::qubit q; - h(q); + x(q); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(q); +#endif } }; -// MLIR-LABEL: func.func @__nvqpp__mlirgen__ak2() +// MLIR-LABEL: func.func @__nvqpp__mlirgen__simple_x() // MLIR-NOT: quake.alloca !quake.ref // MLIR: %[[VAL_0:.*]] = quake.alloca !quake.veq<1> // MLIR-NEXT: %[[VAL_1:.*]] = quake.extract_ref %[[VAL_0]][0] : (!quake.veq<1>) -> !quake.ref int main() { - auto counts = cudaq::sample(ak2{}); - std::cout << "Test: "; - counts.dump(); + auto result = cudaq::sample(simple_x{}); + +#ifndef SYNTAX_CHECK + std::cout << result.most_probable() << '\n'; + assert("1" == result.most_probable()); +#endif + return 0; } + +// CHECK: 1 \ No newline at end of file diff --git a/test/NVQPP/test-0.cpp b/test/NVQPP/integration/callable_kernel_arg.cpp similarity index 79% rename from test/NVQPP/test-0.cpp rename to test/NVQPP/integration/callable_kernel_arg.cpp index dc0caa2515..d046aa18f7 100644 --- a/test/NVQPP/test-0.cpp +++ b/test/NVQPP/integration/callable_kernel_arg.cpp @@ -26,20 +26,24 @@ struct foo { __qpu__ void operator()(CallableKernel &&func, int size) { cudaq::qreg q(size); func(q[0]); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(q[0]); +#endif } }; int main() { - // Not supported?: - // auto result = cudaq::sample(1000, foo{}, &bar); - - // QuakeSynth don't support: auto result = cudaq::sample(1000, foo{}, baz{}, /*qreg size*/ 1); - for (auto &&[bits, counts] : result) { - std::cout << bits << " : " << counts << '\n'; - } + +#ifndef SYNTAX_CHECK + std::cout << result.most_probable() << '\n'; + assert("1" == result.most_probable()); +#endif + return 0; } -// CHECK: 1 : 1000 +// CHECK: 1 diff --git a/test/NVQPP/graph_coloring-1.cpp b/test/NVQPP/integration/graph_coloring-1.cpp similarity index 81% rename from test/NVQPP/graph_coloring-1.cpp rename to test/NVQPP/integration/graph_coloring-1.cpp index a2f1543a2e..f06dbb6c04 100644 --- a/test/NVQPP/graph_coloring-1.cpp +++ b/test/NVQPP/integration/graph_coloring-1.cpp @@ -10,6 +10,7 @@ #include #include +#include struct init_state { __qpu__ void operator()(cudaq::qreg<> &qubits, double theta) { @@ -82,12 +83,19 @@ __qpu__ void grover(double theta) { oracle(qubits, ancilla); reflect_uniform(qubits, theta); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif }; int main() { double theta = 2. * std::acos(1. / std::sqrt(3)); auto result = cudaq::sample(1000, grover, theta); + +#ifndef SYNTAX_CHECK std::vector strings; for (auto &&[bits, count] : result) { strings.push_back(bits); @@ -95,11 +103,28 @@ int main() { std::sort(strings.begin(), strings.end(), [&](auto& a, auto& b) { return result.count(a) > result.count(b); }); + std::unordered_set most_probable; for (auto i = 0; i < 12; ++i) { + most_probable.emplace(strings[i]); for (auto j = 0; j < 8; j += 2) std::cout << strings[i].substr(j, 2) << " "; std::cout << '\n'; } + + assert(most_probable.count("01101101") == 1); + assert(most_probable.count("10110110") == 1); + assert(most_probable.count("11101101") == 1); + assert(most_probable.count("01110110") == 1); + assert(most_probable.count("01100111") == 1); + assert(most_probable.count("01111001") == 1); + assert(most_probable.count("10111001") == 1); + assert(most_probable.count("11011110") == 1); + assert(most_probable.count("11100111") == 1); + assert(most_probable.count("10011011") == 1); + assert(most_probable.count("10011110") == 1); + assert(most_probable.count("11011011") == 1); +#endif + return 0; } diff --git a/test/NVQPP/graph_coloring.cpp b/test/NVQPP/integration/graph_coloring.cpp similarity index 83% rename from test/NVQPP/graph_coloring.cpp rename to test/NVQPP/integration/graph_coloring.cpp index b962de3852..1beb4f912d 100644 --- a/test/NVQPP/graph_coloring.cpp +++ b/test/NVQPP/integration/graph_coloring.cpp @@ -10,6 +10,7 @@ #include #include +#include __qpu__ void init_state(cudaq::qreg<> &qubits, double theta) { ry(theta, qubits[0]); @@ -101,12 +102,19 @@ __qpu__ void grover(double theta) { oracle(qubits, ancilla); reflect_uniform(qubits, theta); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif }; int main() { double theta = 2. * std::acos(1. / std::sqrt(3)); auto result = cudaq::sample(1000, grover, theta); + +#ifndef SYNTAX_CHECK std::vector strings; for (auto &&[bits, count] : result) { strings.push_back(bits); @@ -114,11 +122,29 @@ int main() { std::sort(strings.begin(), strings.end(), [&](auto& a, auto& b) { return result.count(a) > result.count(b); }); + + std::unordered_set most_probable; for (auto i = 0; i < 12; ++i) { + most_probable.emplace(strings[i]); for (auto j = 0; j < 8; j += 2) std::cout << strings[i].substr(j, 2) << " "; std::cout << '\n'; } + + assert(most_probable.count("01101101") == 1); + assert(most_probable.count("10110110") == 1); + assert(most_probable.count("11101101") == 1); + assert(most_probable.count("01110110") == 1); + assert(most_probable.count("01100111") == 1); + assert(most_probable.count("01111001") == 1); + assert(most_probable.count("10111001") == 1); + assert(most_probable.count("11011110") == 1); + assert(most_probable.count("11100111") == 1); + assert(most_probable.count("10011011") == 1); + assert(most_probable.count("10011110") == 1); + assert(most_probable.count("11011011") == 1); +#endif + return 0; } diff --git a/test/NVQPP/if_jit.cpp b/test/NVQPP/integration/if_jit.cpp similarity index 74% rename from test/NVQPP/if_jit.cpp rename to test/NVQPP/integration/if_jit.cpp index dfe53d880d..21a2cda14f 100644 --- a/test/NVQPP/if_jit.cpp +++ b/test/NVQPP/integration/if_jit.cpp @@ -10,19 +10,30 @@ // RUN: nvq++ %s --target quantinuum --emulate -o %t.x && %t.x | FileCheck %s -// CHECK: { 1:100 } - #include +#include __qpu__ void foo(bool value) { cudaq::qubit q; if (value) x(q); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(q); +#endif } int main() { auto result = cudaq::sample(100, foo, true); - result.dump(); + +#ifndef SYNTAX_CHECK + std::cout << result.most_probable() << '\n'; + assert("1" == result.most_probable()); +#endif + return 0; } + +// CHECK: 1 \ No newline at end of file diff --git a/test/NVQPP/test-1.cpp b/test/NVQPP/integration/load_value.cpp similarity index 85% rename from test/NVQPP/test-1.cpp rename to test/NVQPP/integration/load_value.cpp index 961be1a369..bfbb8a236d 100644 --- a/test/NVQPP/test-1.cpp +++ b/test/NVQPP/integration/load_value.cpp @@ -18,13 +18,22 @@ __qpu__ void load_value(unsigned value) { if (value & (1 << i)) x(qubits[3 - i]); } + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif } int main() { for (auto i = 0; i < 16; ++i) { auto result = cudaq::sample(1000, load_value, i); + +#ifndef SYNTAX_CHECK std::cout << result.most_probable() << '\n'; + assert(i == std::stoi(result.most_probable(), nullptr, 2)); +#endif } return 0; } @@ -45,5 +54,3 @@ int main() { // CHECK-NEXT: 1101 // CHECK-NEXT: 1110 // CHECK-NEXT: 1111 - - diff --git a/test/NVQPP/test-4.cpp b/test/NVQPP/integration/qspan_slices.cpp similarity index 78% rename from test/NVQPP/test-4.cpp rename to test/NVQPP/integration/qspan_slices.cpp index 9c796c2938..8ca0172783 100644 --- a/test/NVQPP/test-4.cpp +++ b/test/NVQPP/integration/qspan_slices.cpp @@ -21,17 +21,23 @@ __qpu__ void foo() { cudaq::qreg qubits(4); x(qubits); bar(qubits); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif } int main() { auto result = cudaq::sample(1000, foo); - std::cout << result.size() << '\n'; - for (auto &&[bits, counts] : result) { - std::cout << bits << '\n'; - } + +#ifndef SYNTAX_CHECK + std::cout << result.most_probable() << '\n'; + assert("1110" == result.most_probable()); +#endif + return 0; } -//CHECK: 1 -//CHECK-NEXT: 1110 +//CHECK: 1110 diff --git a/test/NVQPP/sudoku_2x2-1.cpp b/test/NVQPP/integration/sudoku_2x2-1.cpp similarity index 83% rename from test/NVQPP/sudoku_2x2-1.cpp rename to test/NVQPP/integration/sudoku_2x2-1.cpp index 1dc5fda663..4fb9dfa15e 100644 --- a/test/NVQPP/sudoku_2x2-1.cpp +++ b/test/NVQPP/integration/sudoku_2x2-1.cpp @@ -11,6 +11,7 @@ #include #include #include +#include __qpu__ void reflect_uniform(cudaq::qreg<> &qubits) { h(qubits); @@ -39,13 +40,18 @@ __qpu__ void grover() { oracle(qubits, ancilla); reflect_uniform(qubits); } + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif }; int main() { auto result = cudaq::sample(1000, grover); - // Didn't work: - // std::vector strings = result.sequential_data(); + +#ifndef SYNTAX_CHECK std::vector strings; for (auto &&[bits, count] : result) { strings.push_back(bits); @@ -55,6 +61,12 @@ int main() { }); std::cout << strings[0] << '\n'; std::cout << strings[1] << '\n'; + + std::unordered_set most_probable{strings[0], strings[1]}; + assert(most_probable.count("1001") == 1); + assert(most_probable.count("0110") == 1); +#endif + return 0; } diff --git a/test/NVQPP/sudoku_2x2.cpp b/test/NVQPP/integration/sudoku_2x2.cpp similarity index 82% rename from test/NVQPP/sudoku_2x2.cpp rename to test/NVQPP/integration/sudoku_2x2.cpp index a9c65c12b7..3e53610d47 100644 --- a/test/NVQPP/sudoku_2x2.cpp +++ b/test/NVQPP/integration/sudoku_2x2.cpp @@ -11,6 +11,7 @@ #include #include #include +#include __qpu__ void reflect_uniform(cudaq::qreg<> &qubits) { h(qubits); @@ -38,13 +39,18 @@ __qpu__ void grover() { reflect_uniform(qubits); oracle(qubits, ancilla); reflect_uniform(qubits); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif }; int main() { auto result = cudaq::sample(1000, grover); - // Didn't work: - // std::vector strings = result.sequential_data(); + +#ifndef SYNTAX_CHECK std::vector strings; for (auto &&[bits, count] : result) { strings.push_back(bits); @@ -54,6 +60,12 @@ int main() { }); std::cout << strings[0] << '\n'; std::cout << strings[1] << '\n'; + + std::unordered_set most_probable{strings[0], strings[1]}; + assert(most_probable.count("1001") == 1); + assert(most_probable.count("0110") == 1); +#endif + return 0; } diff --git a/test/NVQPP/quantinuumSwapDecomp.cpp b/test/NVQPP/integration/swap_gate.cpp similarity index 80% rename from test/NVQPP/quantinuumSwapDecomp.cpp rename to test/NVQPP/integration/swap_gate.cpp index 1c0bebb6ec..4f3e46835a 100644 --- a/test/NVQPP/quantinuumSwapDecomp.cpp +++ b/test/NVQPP/integration/swap_gate.cpp @@ -17,11 +17,22 @@ int main() { cudaq::qreg q(2); x(q[0]); swap(q[0], q[1]); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(q); +#endif }; auto counts = cudaq::sample(swapKernel); + +#ifndef SYNTAX_CHECK std::cout << counts.most_probable() << '\n'; + assert("01" == counts.most_probable()); +#endif + + return 0; } // CHECK: 01 \ No newline at end of file diff --git a/test/NVQPP/test-int8_t.cpp b/test/NVQPP/integration/test-int8_t.cpp similarity index 81% rename from test/NVQPP/test-int8_t.cpp rename to test/NVQPP/integration/test-int8_t.cpp index a7f5114aaa..681e0c3a9b 100644 --- a/test/NVQPP/test-int8_t.cpp +++ b/test/NVQPP/integration/test-int8_t.cpp @@ -14,15 +14,25 @@ struct variable_qreg { __qpu__ void operator()(std::uint8_t value) { cudaq::qreg qubits(value); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif } }; int main() { for (auto i = 1; i < 5; ++i) { auto result = cudaq::sample(1000, variable_qreg{}, i); + +#ifndef SYNTAX_CHECK std::cout << result.most_probable() << '\n'; + assert(std::string(i, '0') == result.most_probable()); +#endif } + return 0; } diff --git a/test/NVQPP/test-int8_t_free_func.cpp b/test/NVQPP/integration/test-int8_t_free_func.cpp similarity index 81% rename from test/NVQPP/test-int8_t_free_func.cpp rename to test/NVQPP/integration/test-int8_t_free_func.cpp index 62440ed5e0..892af9df73 100644 --- a/test/NVQPP/test-int8_t_free_func.cpp +++ b/test/NVQPP/integration/test-int8_t_free_func.cpp @@ -13,14 +13,24 @@ __qpu__ void variable_qreg(std::uint8_t value) { cudaq::qreg qubits(value); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif } int main() { for (auto i = 1; i < 5; ++i) { auto result = cudaq::sample(1000, variable_qreg, i); + +#ifndef SYNTAX_CHECK std::cout << result.most_probable() << '\n'; + assert(std::string(i, '0') == result.most_probable()); +#endif } + return 0; } diff --git a/test/NVQPP/test-5.cpp b/test/NVQPP/integration/variable_size_qreg.cpp similarity index 81% rename from test/NVQPP/test-5.cpp rename to test/NVQPP/integration/variable_size_qreg.cpp index 240c9fc3c8..c5ca40066f 100644 --- a/test/NVQPP/test-5.cpp +++ b/test/NVQPP/integration/variable_size_qreg.cpp @@ -13,14 +13,24 @@ __qpu__ void variable_qreg(unsigned value) { cudaq::qreg qubits(value); + +// TODO: Extend measurement support for submissions to IonQ, +// see https://github.com/NVIDIA/cuda-quantum/issues/512. +#ifndef IONQ_TARGET mz(qubits); +#endif } int main() { for (auto i = 1; i < 5; ++i) { auto result = cudaq::sample(1000, variable_qreg, i); + +#ifndef SYNTAX_CHECK std::cout << result.most_probable() << '\n'; + assert(std::string(i, '0') == result.most_probable()); +#endif } + return 0; }