From 64bbbc3171003a50898164385f38086f6a9b46ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 17:53:18 +0100 Subject: [PATCH 1/7] Bump pypa/gh-action-pypi-publish in /.github/workflows (#302) --- .github/workflows/assets.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/assets.yaml b/.github/workflows/assets.yaml index 35febeb0..3adec370 100644 --- a/.github/workflows/assets.yaml +++ b/.github/workflows/assets.yaml @@ -85,7 +85,7 @@ jobs: uses: actions/download-artifact@v4 id: download - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@v1.12.4 + uses: pypa/gh-action-pypi-publish@v1.13.0 if: ${{ github.event_name == 'release' && github.event.action == 'created' }} with: user: __token__ From a2ab4ae5bde08bd32a49fcd03ac33e5626966b12 Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Tue, 25 Nov 2025 14:29:51 +0100 Subject: [PATCH 2/7] [CQT-427] Add U Z90 and mZ90 gates to parser (#303) --- CHANGELOG.md | 6 ++ conan/profiles/release-clang-emscripten-wasm | 1 + .../instruction/U_param/ast.golden.txt | 71 +++++++++++++++++++ .../integration/instruction/U_param/input.cq | 5 ++ .../U_param/semantic.3.0.golden.txt | 64 +++++++++++++++++ src/v3x/instruction_set.cpp | 10 ++- test/v3x/cpp/test_instruction_set.cpp | 4 +- 7 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 res/v3x/tests/integration/instruction/U_param/ast.golden.txt create mode 100644 res/v3x/tests/integration/instruction/U_param/input.cq create mode 100644 res/v3x/tests/integration/instruction/U_param/semantic.3.0.golden.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 620cd29d..2774268f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). - **Fixed** for any bug fixes. - **Removed** for now removed features. +## [ M.m.P ] - [ yyyy-mm-dd ] + +### Added +- `U`, `Z90`, and `mZ90` unitary instructions. + + ## [ 1.2.1 ] - [ 2025-07-28 ] ### Added diff --git a/conan/profiles/release-clang-emscripten-wasm b/conan/profiles/release-clang-emscripten-wasm index e7108395..bbfb9c98 100644 --- a/conan/profiles/release-clang-emscripten-wasm +++ b/conan/profiles/release-clang-emscripten-wasm @@ -4,3 +4,4 @@ os=Emscripten build_type=Release compiler=clang compiler.version=14 +compiler.cppstd=20 \ No newline at end of file diff --git a/res/v3x/tests/integration/instruction/U_param/ast.golden.txt b/res/v3x/tests/integration/instruction/U_param/ast.golden.txt new file mode 100644 index 00000000..5f22c781 --- /dev/null +++ b/res/v3x/tests/integration/instruction/U_param/ast.golden.txt @@ -0,0 +1,71 @@ +SUCCESS +Program( + version: < + Version( # input.cq:1:9..12 + items: 3.0 + ) + > + block: < + GlobalBlock( + statements: [ + Variable( # input.cq:3:7..8 + name: < + Identifier( + name: q + ) + > + typ: < + Type( # input.cq:3:1..6 + name: < + Keyword( + name: qubit + ) + > + size: - + ) + > + annotations: [] + ) + GateInstruction( # input.cq:5:1..2 + gate: < + Gate( # input.cq:5:1..2 + name: < + Identifier( + name: U + ) + > + gate: - + parameters: < + ExpressionList( + items: [ + IntegerLiteral( # input.cq:5:3..4 + value: 1 + ) + IntegerLiteral( # input.cq:5:5..6 + value: 2 + ) + IntegerLiteral( # input.cq:5:7..8 + value: 3 + ) + ] + ) + > + annotations: [] + ) + > + operands: < + ExpressionList( + items: [ + Identifier( # input.cq:5:10..11 + name: q + ) + ] + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v3x/tests/integration/instruction/U_param/input.cq b/res/v3x/tests/integration/instruction/U_param/input.cq new file mode 100644 index 00000000..8544ded3 --- /dev/null +++ b/res/v3x/tests/integration/instruction/U_param/input.cq @@ -0,0 +1,5 @@ +version 3.0 + +qubit q + +U(1,2,3) q diff --git a/res/v3x/tests/integration/instruction/U_param/semantic.3.0.golden.txt b/res/v3x/tests/integration/instruction/U_param/semantic.3.0.golden.txt new file mode 100644 index 00000000..f0ff3f8d --- /dev/null +++ b/res/v3x/tests/integration/instruction/U_param/semantic.3.0.golden.txt @@ -0,0 +1,64 @@ +SUCCESS +Program( + api_version: 3.0 + version: < + Version( + items: 3.0 + ) + > + block: < + Block( + statements: [ + GateInstruction( + instruction_ref: U(qubit) + gate: < + Gate( + name: U + gate: - + parameters: [ + ConstFloat( + value: 1 + ) + ConstFloat( + value: 2 + ) + ConstFloat( + value: 3 + ) + ] + annotations: [] + ) + > + operands: [ + VariableRef( + variable --> < + Variable( + name: q + typ: < + Qubit( + size: 1 + ) + > + annotations: [] + ) + > + ) + ] + annotations: [] + ) + ] + ) + > + variables: [ + Variable( + name: q + typ: < + Qubit( + size: 1 + ) + > + annotations: [] + ) + ] +) + diff --git a/src/v3x/instruction_set.cpp b/src/v3x/instruction_set.cpp index 9b1e68d9..ddd84544 100644 --- a/src/v3x/instruction_set.cpp +++ b/src/v3x/instruction_set.cpp @@ -33,6 +33,8 @@ InstructionSet::InstructionSet() { "mX90", { std::nullopt, "V" } }, { "mY90", { std::nullopt, "Q" } }, { "mY90", { std::nullopt, "V" } }, + { "mZ90", { std::nullopt, "Q" } }, + { "mZ90", { std::nullopt, "V" } }, { "Rn", { "fffff", "Q" } }, { "Rn", { "fffff", "V" } }, { "Rx", { "f", "Q" } }, @@ -53,6 +55,8 @@ InstructionSet::InstructionSet() { "T", { std::nullopt, "V" } }, { "Tdag", { std::nullopt, "Q" } }, { "Tdag", { std::nullopt, "V" } }, + { "U", { "fff", "Q" } }, + { "U", { "fff", "V" } }, { "X", { std::nullopt, "Q" } }, { "X", { std::nullopt, "V" } }, { "X90", { std::nullopt, "Q" } }, @@ -62,7 +66,9 @@ InstructionSet::InstructionSet() { "Y90", { std::nullopt, "Q" } }, { "Y90", { std::nullopt, "V" } }, { "Z", { std::nullopt, "Q" } }, - { "Z", { std::nullopt, "V" } } + { "Z", { std::nullopt, "V" } }, + { "Z90", { std::nullopt, "Q" } }, + { "Z90", { std::nullopt, "V" } } } , non_gate_map{ { "measure", { std::nullopt, "BQ" } }, @@ -84,7 +90,7 @@ InstructionSet::InstructionSet() { "ctrl", std::nullopt }, } , single_qubit_named_gate_list{ - "H", "I", "mX90", "mY90", "Rn", "Rx", "Ry", "Rz", "S", "Sdag", "T", "Tdag", "X", "X90", "Y", "Y90", "Z" + "H", "I", "mX90", "mY90", "mZ90", "Rn", "Rx", "Ry", "Rz", "S", "Sdag", "T", "Tdag", "U", "X", "X90", "Y", "Y90", "Z", "Z90" } , two_qubit_named_gate_list{ "CNOT", "CR", "CRk", "CZ", "SWAP" diff --git a/test/v3x/cpp/test_instruction_set.cpp b/test/v3x/cpp/test_instruction_set.cpp index 9df25bd6..55d66b40 100644 --- a/test/v3x/cpp/test_instruction_set.cpp +++ b/test/v3x/cpp/test_instruction_set.cpp @@ -18,10 +18,10 @@ class InstructionSetTest : public ::testing::Test { const InstructionListT& single_qubit_named_gate_list = instruction_set.get_single_qubit_named_gate_list(); const InstructionListT& two_qubit_named_gate_list = instruction_set.get_two_qubit_named_gate_list(); - const size_t number_of_gate_map_entries = 54; + const size_t number_of_gate_map_entries = 60; const size_t number_of_non_gate_map_entries = 12; const size_t number_of_gate_modifier_map_entries = 3; - const size_t number_of_single_qubit_named_gates = 17; + const size_t number_of_single_qubit_named_gates = 20; const size_t number_of_two_qubit_named_gates = 5; }; From e6b46befe6936cdc3744376014fdf67c30ca0396 Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Mon, 23 Mar 2026 11:50:12 +0100 Subject: [PATCH 3/7] [CQT-444] Enable extra parameters overload for measure instruction. (#305) --- .github/workflows/assets.yaml | 2 +- .github/workflows/test.yaml | 4 ++-- CHANGELOG.md | 1 + include/libqasm/v3x/instruction_set.hpp | 2 ++ src/v3x/CqasmParser.g4 | 2 +- src/v3x/instruction_set.cpp | 22 +++++++++++++++++ src/v3x/semantic_analyzer.cpp | 32 +++++++++++++++++++++++++ src/v3x/syntactic_analyzer.cpp | 4 +++- test/v3x/cpp/test_instruction_set.cpp | 8 ++++++- test/v3x/python/test_v3x_analyzer.py | 22 ++++++++++++++++- 10 files changed, 92 insertions(+), 7 deletions(-) diff --git a/.github/workflows/assets.yaml b/.github/workflows/assets.yaml index 3adec370..1837dd65 100644 --- a/.github/workflows/assets.yaml +++ b/.github/workflows/assets.yaml @@ -16,7 +16,7 @@ jobs: matrix: os: [ ubuntu-latest, # Linux/x64 - macos-13, # MacOS/x64 + macos-15-intel, # MacOS/x64 windows-latest, # Windows/x64 ubuntu-24.04-arm, # Linux/ARM64 macos-14 # MacOS/ARM64 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8f35399d..766c00f3 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -62,7 +62,7 @@ jobs: cpp-macos-x64: name: "C++ tests (clang/MacOS/x64)" - runs-on: macos-13 # x64 + runs-on: macos-15-intel # x64 strategy: fail-fast: false matrix: @@ -213,7 +213,7 @@ jobs: python-macos-x64: name: "Python tests (macOS/x64)" - runs-on: macos-13 + runs-on: macos-15-intel steps: - name: Checkout uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2774268f..d961049e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - `U`, `Z90`, and `mZ90` unitary instructions. +- The `measure` instruction also accepts (3 float) parameters to specify measurement axis. ## [ 1.2.1 ] - [ 2025-07-28 ] diff --git a/include/libqasm/v3x/instruction_set.hpp b/include/libqasm/v3x/instruction_set.hpp index ad008e0e..aa6af2f9 100644 --- a/include/libqasm/v3x/instruction_set.hpp +++ b/include/libqasm/v3x/instruction_set.hpp @@ -84,6 +84,8 @@ class InstructionSet { [[nodiscard]] std::optional get_non_gate_param_types(const std::string& name) const; [[nodiscard]] std::optional get_gate_modifier_param_types(const std::string& name) const; [[nodiscard]] std::optional get_instruction_param_types(const std::string& name) const; + [[nodiscard]] std::optional get_non_gate_param_types_with_param_count( + const std::string& name, size_t param_count) const; }; } // namespace cqasm::v3x::instruction diff --git a/src/v3x/CqasmParser.g4 b/src/v3x/CqasmParser.g4 index f83a7700..2044b7e8 100644 --- a/src/v3x/CqasmParser.g4 +++ b/src/v3x/CqasmParser.g4 @@ -48,7 +48,7 @@ gate: // Current implementation of the semantic parser will expect a constant integer // for the first expression in the WAIT instruction nonGateInstruction: - expression EQUALS MEASURE expression # measureInstruction + expression EQUALS MEASURE (OPEN_PARENS expressionList CLOSE_PARENS)? expression # measureInstruction | RESET expression # resetInstruction | INIT expression # initInstruction | BARRIER expression # barrierInstruction diff --git a/src/v3x/instruction_set.cpp b/src/v3x/instruction_set.cpp index ddd84544..ab62438f 100644 --- a/src/v3x/instruction_set.cpp +++ b/src/v3x/instruction_set.cpp @@ -75,6 +75,10 @@ InstructionSet::InstructionSet() { "measure", { std::nullopt, "WV" } }, { "measure", { std::nullopt, "BV" } }, { "measure", { std::nullopt, "WQ" } }, + { "measure", { "fff", "BQ" } }, + { "measure", { "fff", "WV" } }, + { "measure", { "fff", "BV" } }, + { "measure", { "fff", "WQ" } }, { "reset", { std::nullopt, "Q" } }, { "reset", { std::nullopt, "V" } }, { "init", { std::nullopt, "Q" } }, @@ -248,4 +252,22 @@ InstructionSet::InstructionSet() throw error::AnalysisError{ fmt::format("couldn't find instruction '{}'", name) }; } +[[nodiscard]] std::optional InstructionSet::get_non_gate_param_types_with_param_count( + const std::string& name, size_t param_count) const { + const auto& range = non_gate_map.equal_range(name); + for (auto it = range.first; it != range.second; ++it) { + const auto& param_types = it->second.first; + if (!param_types.has_value()) { + if (param_count == 0) { + return param_types; + } + } else { + if (param_types->size() == param_count) { + return param_types; + } + } + } + return std::nullopt; +} + } // namespace cqasm::v3x::instruction diff --git a/src/v3x/semantic_analyzer.cpp b/src/v3x/semantic_analyzer.cpp index b32b0e0a..56459926 100644 --- a/src/v3x/semantic_analyzer.cpp +++ b/src/v3x/semantic_analyzer.cpp @@ -217,6 +217,38 @@ bool is_two_qubit_gate(const tree::One& gate) { values::Values resolve_parameters(const std::string& instruction_name, const values::Values& parameters) { auto ret = values::Values{}; const auto& instruction_set = InstructionSet::get_instance(); + + if (instruction_set.is_non_gate(instruction_name)) { + const auto& param_types = + instruction_set.get_non_gate_param_types_with_param_count(instruction_name, parameters.size()); + bool found_with_zero_params = (!param_types.has_value() && parameters.empty()); + + if (!found_with_zero_params && !param_types.has_value()) { + throw error::AnalysisError{ fmt::format("instruction '{}' does not have an overload with {} parameters.", + instruction_name, + parameters.size()) }; + } + + if (found_with_zero_params) { + return ret; + } // No parameters expected, and none provided — return empty result + + if (param_types.has_value()) { + std::for_each(param_types->begin(), + param_types->end(), + [i = 0, &instruction_name, ¶meters, &ret](const auto& param_type) mutable { + if (!values::check_promote(values::type_of(parameters[i]), types::from_spec(param_type))) { + throw error::AnalysisError{ fmt::format("failed to resolve '{}' with parameter type ({})", + instruction_name, + values::type_of(parameters[i])) }; + } + ret.add(promote(parameters[i], types::from_spec(param_type))); + i++; + }); + } + return ret; + } + const auto& param_types = instruction_set.get_instruction_param_types(instruction_name); if (!param_types.has_value()) { if (!parameters.empty()) { diff --git a/src/v3x/syntactic_analyzer.cpp b/src/v3x/syntactic_analyzer.cpp index 50dfb7f0..b781aa1c 100644 --- a/src/v3x/syntactic_analyzer.cpp +++ b/src/v3x/syntactic_analyzer.cpp @@ -225,7 +225,9 @@ std::any SyntacticAnalyzer::visitNamedGate(CqasmParser::NamedGateContext* contex std::any SyntacticAnalyzer::visitMeasureInstruction(CqasmParser::MeasureInstructionContext* context) { auto ret = tree::make(); ret->name = tree::make(context->MEASURE()->getText()); - ret->parameters = tree::make(); + ret->parameters = context->expressionList() + ? std::any_cast>(visitExpressionList(context->expressionList())) + : tree::make(); ret->operands = tree::make(); ret->operands->items.add(std::any_cast>(context->expression(0)->accept(this))); ret->operands->items.add(std::any_cast>(context->expression(1)->accept(this))); diff --git a/test/v3x/cpp/test_instruction_set.cpp b/test/v3x/cpp/test_instruction_set.cpp index 55d66b40..893428ec 100644 --- a/test/v3x/cpp/test_instruction_set.cpp +++ b/test/v3x/cpp/test_instruction_set.cpp @@ -19,7 +19,7 @@ class InstructionSetTest : public ::testing::Test { const InstructionListT& two_qubit_named_gate_list = instruction_set.get_two_qubit_named_gate_list(); const size_t number_of_gate_map_entries = 60; - const size_t number_of_non_gate_map_entries = 12; + const size_t number_of_non_gate_map_entries = 16; const size_t number_of_gate_modifier_map_entries = 3; const size_t number_of_single_qubit_named_gates = 20; const size_t number_of_two_qubit_named_gates = 5; @@ -180,3 +180,9 @@ TEST_F(InstructionSetTest, get_instruction_param_type) { EXPECT_THAT([this]() { (void)instruction_set.get_instruction_param_types("1q_H"); }, ThrowsMessage(::testing::HasSubstr("couldn't find instruction"))); } + +TEST_F(InstructionSetTest, get_non_gate_param_types_with_param_count) { + EXPECT_EQ(instruction_set.get_non_gate_param_types_with_param_count("measure", 0), std::nullopt); + EXPECT_EQ(instruction_set.get_non_gate_param_types_with_param_count("measure", 3), "fff"); + EXPECT_EQ(instruction_set.get_non_gate_param_types_with_param_count("measure", 1), std::nullopt); +} diff --git a/test/v3x/python/test_v3x_analyzer.py b/test/v3x/python/test_v3x_analyzer.py index ec82b2a0..207d4d13 100644 --- a/test/v3x/python/test_v3x_analyzer.py +++ b/test/v3x/python/test_v3x_analyzer.py @@ -4,6 +4,27 @@ class TestV3xAnalyzer(unittest.TestCase): + + def test_measure_instruction_overload(self): + program_str = "version 3;qubit q;bit b;b = measure q;b = measure(1,0,0) q" + v3x_analyzer = cq.Analyzer() + ast = v3x_analyzer.analyze_string(program_str) + + measure_no_param = ast.block.statements[0] + self.assertEqual(measure_no_param.name, "measure") + + measure_param = ast.block.statements[1] + self.assertEqual(measure_param.name, "measure") + self.assertEqual(measure_param.parameters[0].value, 1) + self.assertEqual(measure_param.parameters[1].value, 0) + self.assertEqual(measure_param.parameters[2].value, 0) + + program_str_invalid_param = "version 3;qubit q;bit b;b = measure(1,0) q" + v3x_analyzer_invalid_param = cq.Analyzer() + errors = v3x_analyzer_invalid_param.analyze_string(program_str_invalid_param) + expected_errors = ["Error at :1:29..36: instruction 'measure' does not have an overload with 2 parameters."] + self.assertEqual(errors, expected_errors) + def test_parse_string_returning_ast(self): program_str = "version 3;qubit[5] q;bit[5] b;H q[0:4];b = measure q" v3x_analyzer = cq.Analyzer() @@ -38,7 +59,6 @@ def test_parse_string_returning_errors(self): program_str = "version 3;qubit[5] q;bit[5] b;H q[0:4];b = measure" v3x_analyzer = cq.Analyzer() errors = v3x_analyzer.parse_string(program_str) - print(errors) expected_errors = ["Error at :1:51: mismatched input '' expecting {'(', '+', '-', '~', '!', BOOLEAN_LITERAL, INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER}"] self.assertEqual(errors, expected_errors) From 1f44891cf637713d6818aafb4bb0c32d982a4dbd Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:27:07 +0100 Subject: [PATCH 4/7] Force source builds over prebuilt Conan binaries. (#306) --- .github/workflows/assets.yaml | 1 + setup.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/assets.yaml b/.github/workflows/assets.yaml index 1837dd65..63c061af 100644 --- a/.github/workflows/assets.yaml +++ b/.github/workflows/assets.yaml @@ -32,6 +32,7 @@ jobs: run: | python -m cibuildwheel --output-dir wheelhouse env: + CIBW_ENVIRONMENT_LINUX: LIBQASM_CONAN_BUILD_PATTERNS="m4/* bison/* flex/*" CIBW_BEFORE_ALL_LINUX: ${{ (matrix.os == 'ubuntu-24.04-arm') && 'yum install -y java-11-openjdk' || ':' }} - uses: actions/upload-artifact@v4 with: diff --git a/setup.py b/setup.py index a17d00df..40c29a00 100755 --- a/setup.py +++ b/setup.py @@ -93,6 +93,11 @@ def run(self): with local.cwd(root_dir): build_type = os.environ.get('CMAKE_BUILD_TYPE', 'Release') build_tests = os.environ.get('LIBQASM_BUILD_TESTS', 'False') + # Optional Conan build patterns to force source builds (e.g. m4/flex/bison in manylinux). + extra_build_patterns = [ + pattern for pattern in os.environ.get('LIBQASM_CONAN_BUILD_PATTERNS', '').split() + if pattern + ] cmd = local['conan']['profile']['detect']['--force'] cmd & FG @@ -116,6 +121,8 @@ def run(self): ['-b']['missing'] ['-tf'][''] ) + for pattern in extra_build_patterns: + cmd = cmd['-b'][pattern] if build_tests == 'True': cmd = cmd['-c']['tools.build:skip_test=False'] if platform.system() == 'Darwin': From 2c4fcd9841198c8a1562bb66e1165cee96a1b30c Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Mon, 23 Mar 2026 16:49:19 +0100 Subject: [PATCH 5/7] Creating release 1.3.0 (#307) --- CHANGELOG.md | 2 +- emscripten/test_libqasm.ts | 2 +- include/libqasm/versioning.hpp | 4 ++-- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d961049e..5b88a591 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - **Fixed** for any bug fixes. - **Removed** for now removed features. -## [ M.m.P ] - [ yyyy-mm-dd ] +## [ 1.3.0 ] - [ 2026-03-23 ] ### Added - `U`, `Z90`, and `mZ90` unitary instructions. diff --git a/emscripten/test_libqasm.ts b/emscripten/test_libqasm.ts index e6f3ba75..2202b3a9 100644 --- a/emscripten/test_libqasm.ts +++ b/emscripten/test_libqasm.ts @@ -8,7 +8,7 @@ wrapper().then(function(result: any) { try { let output = cqasm.get_version() - let expected_output = "1.2.1" + let expected_output = "1.3.0" console.log("\nThe version of libqasm compiled with emscripten is:", output); if (output !== expected_output) { console.log("\tExpected output:", expected_output) diff --git a/include/libqasm/versioning.hpp b/include/libqasm/versioning.hpp index 2c65635d..2a0ec6c1 100644 --- a/include/libqasm/versioning.hpp +++ b/include/libqasm/versioning.hpp @@ -2,8 +2,8 @@ namespace cqasm { -static const char* version{ "1.2.1" }; -static const char* release_year{ "2025" }; +static const char* version{ "1.3.0" }; +static const char* release_year{ "2026" }; [[nodiscard]] [[maybe_unused]] static const char* get_version() { return version; diff --git a/package.json b/package.json index 7a930d85..907baaef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libqasm", - "version": "1.2.1", + "version": "1.3.0", "repository": { "type": "git", "url": "https://github.com/QuTech-Delft/libqasm.git" From 015b2422492da1fd068023b616413efd9ca04c0f Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Mon, 18 May 2026 10:02:04 +0200 Subject: [PATCH 6/7] [CQT-450] Update libQASM (#311) --- .github/actions/cpp-tests/action.yaml | 1 - include/libqasm/v3x/instruction_set.hpp | 3 +- src/v3x/instruction_set.cpp | 65 +++++++++++++++++++++++-- test/v3x/cpp/test_instruction_set.cpp | 12 +++-- 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/.github/actions/cpp-tests/action.yaml b/.github/actions/cpp-tests/action.yaml index d5e95f19..eeda1180 100644 --- a/.github/actions/cpp-tests/action.yaml +++ b/.github/actions/cpp-tests/action.yaml @@ -21,7 +21,6 @@ runs: - name: Install conan run: | pipx install conan - pipx inject conan setuptools shell: ${{ inputs.shell }} - name: Get latest CMake uses: lukka/get-cmake@latest diff --git a/include/libqasm/v3x/instruction_set.hpp b/include/libqasm/v3x/instruction_set.hpp index aa6af2f9..74db90c2 100644 --- a/include/libqasm/v3x/instruction_set.hpp +++ b/include/libqasm/v3x/instruction_set.hpp @@ -25,6 +25,7 @@ class InstructionSet { InstructionListT single_qubit_named_gate_list; InstructionListT two_qubit_named_gate_list; InstructionListT non_gate_list; + InstructionListT measure_list; InstructionSet(); @@ -34,7 +35,6 @@ class InstructionSet { std::string single_qubit_gate_composition_prefix = "1q"; std::string two_qubit_gate_composition_prefix = "2q"; - std::string measure_name = "measure"; std::string reset_name = "reset"; std::string init_name = "init"; std::string barrier_name = "barrier"; @@ -53,6 +53,7 @@ class InstructionSet { [[nodiscard]] const InstructionListT& get_single_qubit_named_gate_list() const; [[nodiscard]] const InstructionListT& get_two_qubit_named_gate_list() const; [[nodiscard]] const InstructionListT& get_non_gate_list() const; + [[nodiscard]] const InstructionListT& get_measure_list() const; [[nodiscard]] bool is_single_qubit_named_gate(const std::string& name) const; [[nodiscard]] bool is_two_qubit_named_gate(const std::string& name) const; diff --git a/src/v3x/instruction_set.cpp b/src/v3x/instruction_set.cpp index ab62438f..22e6d8a8 100644 --- a/src/v3x/instruction_set.cpp +++ b/src/v3x/instruction_set.cpp @@ -21,14 +21,46 @@ InstructionSet::InstructionSet() { "CRk", { "i", "QV" } }, { "CRk", { "i", "VQ" } }, { "CRk", { "i", "VV" } }, + { "CV", { std::nullopt, "QQ" } }, + { "CV", { std::nullopt, "QV" } }, + { "CV", { std::nullopt, "VQ" } }, + { "CV", { std::nullopt, "VV" } }, + { "CY", { std::nullopt, "QQ" } }, + { "CY", { std::nullopt, "QV" } }, + { "CY", { std::nullopt, "VQ" } }, + { "CY", { std::nullopt, "VV" } }, { "CZ", { std::nullopt, "QQ" } }, { "CZ", { std::nullopt, "QV" } }, { "CZ", { std::nullopt, "VQ" } }, { "CZ", { std::nullopt, "VV" } }, + { "DCNOT", { std::nullopt, "QQ" } }, + { "DCNOT", { std::nullopt, "QV" } }, + { "DCNOT", { std::nullopt, "VQ" } }, + { "DCNOT", { std::nullopt, "VV" } }, + { "ECR", { std::nullopt, "QQ" } }, + { "ECR", { std::nullopt, "QV" } }, + { "ECR", { std::nullopt, "VQ" } }, + { "ECR", { std::nullopt, "VV" } }, { "H", { std::nullopt, "Q" } }, { "H", { std::nullopt, "V" } }, { "I", { std::nullopt, "Q" } }, { "I", { std::nullopt, "V" } }, + { "InvSqrtSWAP", { std::nullopt, "QQ" } }, + { "InvSqrtSWAP", { std::nullopt, "QV" } }, + { "InvSqrtSWAP", { std::nullopt, "VQ" } }, + { "InvSqrtSWAP", { std::nullopt, "VV" } }, + { "ISWAP", { std::nullopt, "QQ" } }, + { "ISWAP", { std::nullopt, "QV" } }, + { "ISWAP", { std::nullopt, "VQ" } }, + { "ISWAP", { std::nullopt, "VV" } }, + { "M", { std::nullopt, "QQ" } }, + { "M", { std::nullopt, "QV" } }, + { "M", { std::nullopt, "VQ" } }, + { "M", { std::nullopt, "VV" } }, + { "MS", { std::nullopt, "QQ" } }, + { "MS", { std::nullopt, "QV" } }, + { "MS", { std::nullopt, "VQ" } }, + { "MS", { std::nullopt, "VV" } }, { "mX90", { std::nullopt, "Q" } }, { "mX90", { std::nullopt, "V" } }, { "mY90", { std::nullopt, "Q" } }, @@ -47,6 +79,14 @@ InstructionSet::InstructionSet() { "S", { std::nullopt, "V" } }, { "Sdag", { std::nullopt, "Q" } }, { "Sdag", { std::nullopt, "V" } }, + { "SqrtISWAP", { std::nullopt, "QQ" } }, + { "SqrtISWAP", { std::nullopt, "QV" } }, + { "SqrtISWAP", { std::nullopt, "VQ" } }, + { "SqrtISWAP", { std::nullopt, "VV" } }, + { "SqrtSWAP", { std::nullopt, "QQ" } }, + { "SqrtSWAP", { std::nullopt, "QV" } }, + { "SqrtSWAP", { std::nullopt, "VQ" } }, + { "SqrtSWAP", { std::nullopt, "VV" } }, { "SWAP", { std::nullopt, "QQ" } }, { "SWAP", { std::nullopt, "QV" } }, { "SWAP", { std::nullopt, "VQ" } }, @@ -75,6 +115,18 @@ InstructionSet::InstructionSet() { "measure", { std::nullopt, "WV" } }, { "measure", { std::nullopt, "BV" } }, { "measure", { std::nullopt, "WQ" } }, + { "measureX", { std::nullopt, "BQ" } }, + { "measureX", { std::nullopt, "WV" } }, + { "measureX", { std::nullopt, "BV" } }, + { "measureX", { std::nullopt, "WQ" } }, + { "measureY", { std::nullopt, "BQ" } }, + { "measureY", { std::nullopt, "WV" } }, + { "measureY", { std::nullopt, "BV" } }, + { "measureY", { std::nullopt, "WQ" } }, + { "measureZ", { std::nullopt, "BQ" } }, + { "measureZ", { std::nullopt, "WV" } }, + { "measureZ", { std::nullopt, "BV" } }, + { "measureZ", { std::nullopt, "WQ" } }, { "measure", { "fff", "BQ" } }, { "measure", { "fff", "WV" } }, { "measure", { "fff", "BV" } }, @@ -97,10 +149,13 @@ InstructionSet::InstructionSet() "H", "I", "mX90", "mY90", "mZ90", "Rn", "Rx", "Ry", "Rz", "S", "Sdag", "T", "Tdag", "U", "X", "X90", "Y", "Y90", "Z", "Z90" } , two_qubit_named_gate_list{ - "CNOT", "CR", "CRk", "CZ", "SWAP" + "CNOT", "CR", "CRk", "CV", "CY", "CZ", "DCNOT", "ECR", "InvSqrtSWAP", "ISWAP", "M", "MS", "SqrtISWAP", "SqrtSWAP", "SWAP" } , non_gate_list{ - "measure", "reset", "init", "barrier", "wait" + "measure", "measureX", "measureY", "measureZ", "reset", "init", "barrier", "wait" +} +, measure_list{ + "measure", "measureX", "measureY", "measureZ" } {} // NOLINTEND @@ -134,6 +189,10 @@ InstructionSet::InstructionSet() return non_gate_list; } +[[nodiscard]] const InstructionListT& InstructionSet::get_measure_list() const { + return measure_list; +} + [[nodiscard]] bool InstructionSet::is_single_qubit_named_gate(const std::string& name) const { return single_qubit_named_gate_list.contains(name); } @@ -171,7 +230,7 @@ InstructionSet::InstructionSet() } [[nodiscard]] bool InstructionSet::is_measure(const std::string& name) const { - return name == measure_name; + return measure_list.contains(name); } [[nodiscard]] bool InstructionSet::is_reset(const std::string& name) const { diff --git a/test/v3x/cpp/test_instruction_set.cpp b/test/v3x/cpp/test_instruction_set.cpp index 893428ec..07db93cd 100644 --- a/test/v3x/cpp/test_instruction_set.cpp +++ b/test/v3x/cpp/test_instruction_set.cpp @@ -18,11 +18,11 @@ class InstructionSetTest : public ::testing::Test { const InstructionListT& single_qubit_named_gate_list = instruction_set.get_single_qubit_named_gate_list(); const InstructionListT& two_qubit_named_gate_list = instruction_set.get_two_qubit_named_gate_list(); - const size_t number_of_gate_map_entries = 60; - const size_t number_of_non_gate_map_entries = 16; + const size_t number_of_gate_map_entries = 100; + const size_t number_of_non_gate_map_entries = 28; const size_t number_of_gate_modifier_map_entries = 3; const size_t number_of_single_qubit_named_gates = 20; - const size_t number_of_two_qubit_named_gates = 5; + const size_t number_of_two_qubit_named_gates = 15; }; TEST_F(InstructionSetTest, get_instance) { @@ -105,7 +105,13 @@ TEST_F(InstructionSetTest, is_gate) { } TEST_F(InstructionSetTest, is_measure) { EXPECT_TRUE(instruction_set.is_measure("measure")); + EXPECT_TRUE(instruction_set.is_measure("measureX")); + EXPECT_TRUE(instruction_set.is_measure("measureY")); + EXPECT_TRUE(instruction_set.is_measure("measureZ")); EXPECT_FALSE(instruction_set.is_measure("MEASURE")); + EXPECT_FALSE(instruction_set.is_measure("measure_z")); + EXPECT_FALSE(instruction_set.is_measure("MEASUREz")); + EXPECT_FALSE(instruction_set.is_measure("MEASUREZ")); } TEST_F(InstructionSetTest, is_reset) { EXPECT_TRUE(instruction_set.is_reset("reset")); From afccad43e72f69a1dbff54b53275ad150dc42fc4 Mon Sep 17 00:00:00 2001 From: Chris Elenbaas <67630508+elenbaasc@users.noreply.github.com> Date: Fri, 5 Jun 2026 14:31:48 +0200 Subject: [PATCH 7/7] Creating release 1.4.0 (#312) --- CHANGELOG.md | 6 ++++++ emscripten/test_libqasm.ts | 2 +- include/libqasm/versioning.hpp | 2 +- package.json | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b88a591..d30889ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). - **Fixed** for any bug fixes. - **Removed** for now removed features. +## [ 1.4.0 ] - [ 2026-06-05 ] + +### Added +- `CV`, `CY`, `DCNOT`, `ECR`, `ISWAP`, `InvSqrtSWAP`, `M`, `MS`, `SqrtISWAP`, and `SqrtSWAP` unitary instructions. +- Aliases `measureX`, `measureY`, and `measureZ`, for the `measure` instruction along the respective axes. + ## [ 1.3.0 ] - [ 2026-03-23 ] ### Added diff --git a/emscripten/test_libqasm.ts b/emscripten/test_libqasm.ts index 2202b3a9..ebc49a09 100644 --- a/emscripten/test_libqasm.ts +++ b/emscripten/test_libqasm.ts @@ -8,7 +8,7 @@ wrapper().then(function(result: any) { try { let output = cqasm.get_version() - let expected_output = "1.3.0" + let expected_output = "1.4.0" console.log("\nThe version of libqasm compiled with emscripten is:", output); if (output !== expected_output) { console.log("\tExpected output:", expected_output) diff --git a/include/libqasm/versioning.hpp b/include/libqasm/versioning.hpp index 2a0ec6c1..a147618c 100644 --- a/include/libqasm/versioning.hpp +++ b/include/libqasm/versioning.hpp @@ -2,7 +2,7 @@ namespace cqasm { -static const char* version{ "1.3.0" }; +static const char* version{ "1.4.0" }; static const char* release_year{ "2026" }; [[nodiscard]] [[maybe_unused]] static const char* get_version() { diff --git a/package.json b/package.json index 907baaef..5836d16a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libqasm", - "version": "1.3.0", + "version": "1.4.0", "repository": { "type": "git", "url": "https://github.com/QuTech-Delft/libqasm.git"