diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md index 32b7de372d..235d7c83db 100644 --- a/doc/releases/changelog-dev.md +++ b/doc/releases/changelog-dev.md @@ -39,6 +39,11 @@ into normal PPR and PPMs with SCF dialect to support runtime execution. [(#2390)](https://github.com/PennyLaneAI/catalyst/pull/2390) +* New qubit-type specializations have been added Catalyst's MLIR type system. These new qubit types + include `!quantum.bit`, `!quantum.bit` and `!quantum.bit`. The original + `!quantum.bit` type continues to be supported and used as the default qubit type. + [(#2369)](https://github.com/PennyLaneAI/catalyst/pull/2369) +

Documentation 📝

* Updated the Unified Compiler Cookbook to be compatible with the latest versions of PennyLane and Catalyst. @@ -47,7 +52,8 @@

Contributors ✍️

This release contains contributions from (in alphabetical order): -Ali Asadi +Ali Asadi, +Joey Carter, Sengthai Heng, Jeffrey Kam, Mudit Pandey. diff --git a/mlir/include/Quantum/IR/QuantumAttrDefs.td b/mlir/include/Quantum/IR/QuantumAttrDefs.td index 133462bae1..69854dcd3b 100644 --- a/mlir/include/Quantum/IR/QuantumAttrDefs.td +++ b/mlir/include/Quantum/IR/QuantumAttrDefs.td @@ -38,5 +38,28 @@ def NamedObservable : I32EnumAttr<"NamedObservable", def NamedObservableAttr : EnumAttr; +def QubitLevel : I32EnumAttr<"QubitLevel", + "Qubit levels in the hierarchical qubit representation", + [ + I32EnumAttrCase<"Abstract", 0, "abstract">, + I32EnumAttrCase<"Logical", 1, "logical">, + I32EnumAttrCase<"QEC", 2, "qec">, + I32EnumAttrCase<"Physical", 3, "physical">, + ]> { + let cppNamespace = "catalyst::quantum"; + let genSpecializedAttr = 0; +} + +def QubitRole : I32EnumAttr<"QubitRole", + "Qubit roles for further specialization in the hierarchical qubit representation", + [ + I32EnumAttrCase<"Null", 0, "null">, + I32EnumAttrCase<"Data", 1, "data">, + I32EnumAttrCase<"XCheck", 2, "xcheck">, + I32EnumAttrCase<"ZCheck", 3, "zcheck">, + ]> { + let cppNamespace = "catalyst::quantum"; + let genSpecializedAttr = 0; +} #endif // QUANTUM_ATTR_DEFS diff --git a/mlir/include/Quantum/IR/QuantumInterfaces.td b/mlir/include/Quantum/IR/QuantumInterfaces.td index 1a6f5cd16b..09255206bf 100644 --- a/mlir/include/Quantum/IR/QuantumInterfaces.td +++ b/mlir/include/Quantum/IR/QuantumInterfaces.td @@ -79,11 +79,26 @@ def QuantumOperation : OpInterface<"QuantumOperation"> { let verify = [{ auto gate = mlir::cast($_op); + auto operands = gate.getQubitOperands(); + auto results = gate.getQubitResults(); - if (gate.getQubitOperands().size() != gate.getQubitResults().size()) + if (operands.size() != results.size()) { return $_op->emitError() << - "number of qubits in input (" << gate.getQubitOperands().size() << ") " << - "and output (" << gate.getQubitResults().size() << ") must be the same"; + "number of qubits in input (" << operands.size() << ") " << + "and output (" << results.size() << ") must be the same"; + } + + if (!operands.empty()) { + mlir::Type refType = operands[0].getType(); + + // Check if all operands and results have the same type as refType + auto allMatch = [&](auto value) { return value.getType() == refType; }; + + if (!llvm::all_of(operands, allMatch) || !llvm::all_of(results, allMatch)) { + return $_op->emitOpError() + << "requires all qubit operands and results to have the same type"; + } + } return mlir::success(); }]; diff --git a/mlir/include/Quantum/IR/QuantumOps.td b/mlir/include/Quantum/IR/QuantumOps.td index 165aa880d1..8c1544b3cf 100644 --- a/mlir/include/Quantum/IR/QuantumOps.td +++ b/mlir/include/Quantum/IR/QuantumOps.td @@ -346,7 +346,7 @@ class UnitaryGate_Op traits = []> : let extraClassDeclaration = extraBaseClassDeclaration; } -def SetStateOp : Gate_Op<"set_state"> { +def SetStateOp : Gate_Op<"set_state", [AllTypesMatch<["in_qubits", "out_qubits"]>]> { let summary = "Set state to a complex vector."; let description = [{ This operation is useful for simulators implementing state preparation. @@ -377,7 +377,7 @@ def SetStateOp : Gate_Op<"set_state"> { } -def SetBasisStateOp : Gate_Op<"set_basis_state"> { +def SetBasisStateOp : Gate_Op<"set_basis_state", [AllTypesMatch<["in_qubits", "out_qubits"]>]> { let summary = "Set basis state."; let description = [{ This operation is useful for simulators implementing set basis state. @@ -410,7 +410,9 @@ def SetBasisStateOp : Gate_Op<"set_basis_state"> { } def CustomOp : UnitaryGate_Op<"custom", [DifferentiableGate, NoMemoryEffect, - AttrSizedOperandSegments, AttrSizedResultSegments]> { + AttrSizedOperandSegments, AttrSizedResultSegments, + AllTypesMatch<["in_qubits", "out_qubits"]>, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "A generic quantum gate on n qubits with m floating point parameters."; let description = [{ }]; @@ -537,14 +539,16 @@ def CustomOp : UnitaryGate_Op<"custom", [DifferentiableGate, NoMemoryEffect, def PauliWord : TypedArrayAttrBase; def PauliRotOp : UnitaryGate_Op<"paulirot", [DifferentiableGate, NoMemoryEffect, - AttrSizedOperandSegments, AttrSizedResultSegments]> { + AttrSizedOperandSegments, AttrSizedResultSegments, + AllTypesMatch<["in_qubits", "out_qubits"]>, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "Apply a Pauli Product Rotation"; let description = [{ The `quantum.paulirot` operation applies a rotation around a Pauli product - operator to the state-vector. + operator to the state-vector. The arguments are the rotation angle `angle`, a string representing the Pauli product operator, and a set of qubits the operation acts on. - Note that this operation is currently not excutable. There isn't a valid + Note that this operation is currently not excutable. There isn't a valid lowering path to the LLVM IR. }]; @@ -565,7 +569,7 @@ def PauliRotOp : UnitaryGate_Op<"paulirot", [DifferentiableGate, NoMemoryEffect, let assemblyFormat = [{ $pauli_product `(` $angle `)` $in_qubits (`adj` $adjoint^)? attr-dict ( `ctrls` `(` $in_ctrl_qubits^ `)` )? ( `ctrlvals` `(` $in_ctrl_values^ `)` )? `:` type($out_qubits) (`ctrls` type($out_ctrl_qubits)^ )? }]; - + let extraClassDeclaration = extraBaseClassDeclaration # [{ mlir::ValueRange getAllParams() { return getODSOperands(getParamOperandIdx()); @@ -573,7 +577,8 @@ def PauliRotOp : UnitaryGate_Op<"paulirot", [DifferentiableGate, NoMemoryEffect, }]; } -def GlobalPhaseOp : UnitaryGate_Op<"gphase", [DifferentiableGate, AttrSizedOperandSegments]> { +def GlobalPhaseOp : UnitaryGate_Op<"gphase", [DifferentiableGate, AttrSizedOperandSegments, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "Global Phase."; let description = [{ @@ -614,7 +619,9 @@ def GlobalPhaseOp : UnitaryGate_Op<"gphase", [DifferentiableGate, AttrSizedOpera } def MultiRZOp : UnitaryGate_Op<"multirz", [DifferentiableGate, NoMemoryEffect, - AttrSizedOperandSegments, AttrSizedResultSegments]> { + AttrSizedOperandSegments, AttrSizedResultSegments, + AllTypesMatch<["in_qubits", "out_qubits"]>, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "Apply an arbitrary multi Z rotation"; let description = [{ The `quantum.multirz` operation applies an arbitrary multi Z rotation to the state-vector. @@ -653,7 +660,9 @@ def MultiRZOp : UnitaryGate_Op<"multirz", [DifferentiableGate, NoMemoryEffect, } def PCPhaseOp : UnitaryGate_Op<"pcphase", [DifferentiableGate, NoMemoryEffect, - AttrSizedOperandSegments, AttrSizedResultSegments]> { + AttrSizedOperandSegments, AttrSizedResultSegments, + AllTypesMatch<["in_qubits", "out_qubits"]>, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "Apply a projector-controlled phase gate"; let description = [{ This gate is built from simpler gates like `PhaseShift` and `PauliX` and acts on a group @@ -703,7 +712,9 @@ def PCPhaseOp : UnitaryGate_Op<"pcphase", [DifferentiableGate, NoMemoryEffect, def QubitUnitaryOp : UnitaryGate_Op<"unitary", [ParametrizedGate, NoMemoryEffect, - AttrSizedOperandSegments, AttrSizedResultSegments]> { + AttrSizedOperandSegments, AttrSizedResultSegments, + AllTypesMatch<["in_qubits", "out_qubits"]>, + AllTypesMatch<["in_ctrl_qubits", "out_ctrl_qubits"]>]> { let summary = "Apply an arbitrary fixed unitary matrix"; let description = [{ The `quantum.unitary` operation applies an arbitrary fixed unitary matrix to the @@ -958,7 +969,7 @@ def HamiltonianOp : Observable_Op<"hamiltonian"> { class Measurement_Op traits = []> : Quantum_Op; -def MeasureOp : Quantum_Op<"measure"> { +def MeasureOp : Quantum_Op<"measure", [AllTypesMatch<["in_qubit", "out_qubit"]>]> { let summary = "A single-qubit projective measurement in the computational basis."; let description = [{ }]; diff --git a/mlir/include/Quantum/IR/QuantumTypes.td b/mlir/include/Quantum/IR/QuantumTypes.td index 77a2c02923..01f4909ba1 100644 --- a/mlir/include/Quantum/IR/QuantumTypes.td +++ b/mlir/include/Quantum/IR/QuantumTypes.td @@ -30,6 +30,29 @@ class Quantum_Type traits = []> def QubitType : Quantum_Type<"Qubit", "bit"> { let summary = "A value-semantic qubit (state)."; + + let parameters = (ins + DefaultValuedParameter<"QubitLevel", "QubitLevel::Abstract">:$level, + DefaultValuedParameter<"QubitRole", "QubitRole::Null">:$role + ); + + let assemblyFormat = "(`<` $level^ (`,` $role^ )? `>`)?"; + + // This allows the ODS generator to "build" the type automatically using the + // 'Abstract' qubit level and 'Null' qubit role and when it needs a default. + let builderCall = [{ + $_builder.getType( + quantum::QubitLevel::Abstract, quantum::QubitRole::Null) + }]; + + let extraClassDeclaration = [{ + // Get an instance of the QubitType with the default 'Abstract' level and 'Null' role. + static QubitType get(::mlir::MLIRContext *context) { + return get(context, quantum::QubitLevel::Abstract, quantum::QubitRole::Null); + } + }]; + + let genVerifyDecl = 1; } def QuregType : Quantum_Type<"Qureg", "reg"> { let summary = "An array of value-semantic qubits (i.e. quantum register)."; diff --git a/mlir/lib/Quantum/IR/CMakeLists.txt b/mlir/lib/Quantum/IR/CMakeLists.txt index 976c35cfc1..e229182e4f 100644 --- a/mlir/lib/Quantum/IR/CMakeLists.txt +++ b/mlir/lib/Quantum/IR/CMakeLists.txt @@ -2,6 +2,7 @@ add_mlir_library(MLIRQuantum QuantumDialect.cpp QuantumInterfaces.cpp QuantumOps.cpp + QuantumTypes.cpp ADDITIONAL_HEADER_DIRS ${PROJECT_SOURCE_DIR}/include/Quantum diff --git a/mlir/lib/Quantum/IR/QuantumTypes.cpp b/mlir/lib/Quantum/IR/QuantumTypes.cpp new file mode 100644 index 0000000000..38841be223 --- /dev/null +++ b/mlir/lib/Quantum/IR/QuantumTypes.cpp @@ -0,0 +1,35 @@ +// Copyright 2026 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 "mlir/IR/Diagnostics.h" +#include "mlir/Support/LLVM.h" + +#include "Quantum/IR/QuantumAttrDefs.h" +#include "Quantum/IR/QuantumTypes.h" + +using namespace mlir; +using namespace catalyst::quantum; + +LogicalResult QubitType::verify(function_ref emitError, QubitLevel level, + QubitRole role) +{ + // If qubit level is not QEC or Physical, role must be Null + // In other words, abstract and logical qubits cannot specify a role + if ((level != QubitLevel::QEC && level != QubitLevel::Physical) && role != QubitRole::Null) { + return emitError() << "qubit role '" << stringifyQubitRole(role) + << "' is only permitted for qec and physical qubits; " + << "found level '" << stringifyQubitLevel(level) << "'"; + } + return success(); +} diff --git a/mlir/test/Quantum/QubitTypesTest.mlir b/mlir/test/Quantum/QubitTypesTest.mlir new file mode 100644 index 0000000000..021287098c --- /dev/null +++ b/mlir/test/Quantum/QubitTypesTest.mlir @@ -0,0 +1,354 @@ +// Copyright 2026 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. + +// RUN: quantum-opt %s --split-input-file --verify-diagnostics + +//===----------------------------------------------------------------------===// +// Smoke tests: Can we use each qubit type? +//===----------------------------------------------------------------------===// + +func.func @test_default_type(%0 : !quantum.bit, %1 : !quantum.bit) { + %2 = quantum.custom ""() %0 : !quantum.bit + %3, %4 = quantum.custom ""() %1, %2 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_abstract_type(%0 : !quantum.bit, %1 : !quantum.bit) { + %2 = quantum.custom ""() %0 : !quantum.bit + %3, %4 = quantum.custom ""() %1, %2 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_logical_type(%0 : !quantum.bit, %1 : !quantum.bit) { + %2 = quantum.custom ""() %0 : !quantum.bit + %3, %4 = quantum.custom ""() %1, %2 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_qec_type(%0 : !quantum.bit, %1 : !quantum.bit) { + %2 = quantum.custom ""() %0 : !quantum.bit + %3, %4 = quantum.custom ""() %1, %2 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_physical_type(%0 : !quantum.bit, %1 : !quantum.bit) { + %2 = quantum.custom ""() %0 : !quantum.bit + %3, %4 = quantum.custom ""() %1, %2 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_ctrl_default(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_ctrl_abstract(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_ctrl_logical(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_ctrl_qec(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_ctrl_physical(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_alloc_qb_default() { + %0 = quantum.alloc_qb : !quantum.bit + return +} + +// ----- + +func.func @test_alloc_qb_abs() { + %0 = quantum.alloc_qb : !quantum.bit + return +} + +// ----- + +func.func @test_alloc_qb_log() { + %0 = quantum.alloc_qb : !quantum.bit + return +} + +// ----- + +func.func @test_alloc_qb_phy() { + %0 = quantum.alloc_qb : !quantum.bit + return +} + +// ----- + +func.func @test_dealloc_qb_default(%0 : !quantum.bit) { + quantum.dealloc_qb %0 : !quantum.bit + return +} + +// ----- + +func.func @test_dealloc_qb_abs(%0 : !quantum.bit) { + quantum.dealloc_qb %0 : !quantum.bit + return +} + +// ----- + +func.func @test_dealloc_qb_log(%0 : !quantum.bit) { + quantum.dealloc_qb %0 : !quantum.bit + return +} + +// ----- + +func.func @test_dealloc_qb_phy(%0 : !quantum.bit) { + quantum.dealloc_qb %0 : !quantum.bit + return +} + +// ----- + +func.func @test_abs_null_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_log_null_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_qec_data_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_qec_xcheck_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_qec_zcheck_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_phy_data_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_phy_xcheck_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +func.func @test_phy_zcheck_type(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit + return +} + +// ----- + +//===----------------------------------------------------------------------===// +// Verifier tests: Does incorrect usage result in expected errors? +//===----------------------------------------------------------------------===// + +// COM: In the tests below, note that we can safely "convert" between `!quantum.bit` +// COM: and `!quantum.bit` since they are equivalent. + +func.func @test_mix_types_abs_log(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_mix_types_abs_qec(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_mix_types_abs_phy(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_mix_types_log_qec(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_mix_types_log_phy(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_mix_types_qec_phy(%0 : !quantum.bit) { + %1 = quantum.custom ""() %0 : !quantum.bit // expected-note {{prior use here}} + // expected-error @below {{expects different type than prior uses}} + %2 = quantum.custom ""() %1 : !quantum.bit + return +} + +// ----- + +func.func @test_2q_mix_input_types_default_log(%0 : !quantum.bit, %1 : !quantum.bit) { + // expected-error @below {{requires all qubit operands and results to have the same type}} + %2, %3 = quantum.custom ""() %0, %1 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_2q_mix_input_types_abs_log(%0 : !quantum.bit, %1 : !quantum.bit) { + // expected-error @below {{requires all qubit operands and results to have the same type}} + %2, %3 = quantum.custom ""() %0, %1 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_2q_mix_input_types_abs_phy(%0 : !quantum.bit, %1 : !quantum.bit) { + // expected-error @below {{requires all qubit operands and results to have the same type}} + %2, %3 = quantum.custom ""() %0, %1 : !quantum.bit, !quantum.bit + return +} + +// ----- + +func.func @test_2q_mix_input_ctrl_types_abs_log(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + // expected-error @below {{requires all qubit operands and results to have the same type}} + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_2q_mix_input_ctrl_types_abs_phy(%0 : !quantum.bit, %1 : !quantum.bit) { + %true = llvm.mlir.constant (1 : i1) : i1 + // expected-error @below {{requires all qubit operands and results to have the same type}} + %2, %3 = quantum.custom ""() %0 ctrls (%1) ctrlvals (%true) : !quantum.bit ctrls !quantum.bit + return +} + +// ----- + +func.func @test_abs_data_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'data' is only permitted for qec and physical qubits}} + return +} + +// ----- + +func.func @test_abs_xcheck_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'xcheck' is only permitted for qec and physical qubits}} + return +} + +// ----- + +func.func @test_abs_zcheck_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'zcheck' is only permitted for qec and physical qubits}} + return +} + +// ----- + +func.func @test_abs_data_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'data' is only permitted for qec and physical qubits}} + return +} + +// ----- + +func.func @test_abs_xcheck_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'xcheck' is only permitted for qec and physical qubits}} + return +} + +// ----- + +func.func @test_abs_zcheck_type(%0 : !quantum.bit) { + // expected-error @above {{qubit role 'zcheck' is only permitted for qec and physical qubits}} + return +} diff --git a/mlir/test/Quantum/VerifierTest.mlir b/mlir/test/Quantum/VerifierTest.mlir index f6fbb90ac1..f194356063 100644 --- a/mlir/test/Quantum/VerifierTest.mlir +++ b/mlir/test/Quantum/VerifierTest.mlir @@ -59,7 +59,7 @@ func.func @custom(%f : f64, %q1 : !quantum.bit, %q2 : !quantum.bit) { %q4 = quantum.custom "RZ"(%f) %q1 : !quantum.bit %q5, %q6 = quantum.custom "CNOT"() %q1, %q2 : !quantum.bit, !quantum.bit - // expected-error@+1 {{number of qubits in input (2) and output (1) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %err = quantum.custom "CNOT"() %q1, %q2 : !quantum.bit return @@ -68,7 +68,7 @@ func.func @custom(%f : f64, %q1 : !quantum.bit, %q2 : !quantum.bit) { // ----- func.func @multirz2(%q0 : !quantum.bit, %q1 : !quantum.bit, %theta : f64) { - // expected-error@+1 {{number of qubits in input (2) and output (1) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %err = quantum.multirz(%theta) %q0, %q1 : !quantum.bit return @@ -77,7 +77,7 @@ func.func @multirz2(%q0 : !quantum.bit, %q1 : !quantum.bit, %theta : f64) { // ----- func.func @multirz3(%q0 : !quantum.bit, %theta : f64) { - // expected-error@+1 {{number of qubits in input (1) and output (2) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %err:2 = quantum.multirz(%theta) %q0 : !quantum.bit, !quantum.bit return @@ -86,7 +86,7 @@ func.func @multirz3(%q0 : !quantum.bit, %theta : f64) { // ----- func.func @unitary2(%q0 : !quantum.bit, %q1 : !quantum.bit, %m : tensor<4x4xcomplex>) { - // expected-error@+1 {{number of qubits in input (2) and output (1) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %err = quantum.unitary(%m: tensor<4x4xcomplex>) %q0, %q1 : !quantum.bit return @@ -110,7 +110,7 @@ func.func @controlled1(%1 : !quantum.bit, %2 : !quantum.bit, %3 : !quantum.bit) %cst = llvm.mlir.constant (6.000000e-01 : f64) : f64 %cst_0 = llvm.mlir.constant (9.000000e-01 : f64) : f64 %cst_1 = llvm.mlir.constant (3.000000e-01 : f64) : f64 - // expected-error@+1 {{number of controlling qubits in input (1) and output (0) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %out_qubits:2 = quantum.custom "Rot"(%cst, %cst_1, %cst_0) %2 ctrls (%3) ctrlvals (%true) : !quantum.bit, !quantum.bit return } @@ -122,7 +122,7 @@ func.func @controlled2(%1 : !quantum.bit, %2 : !quantum.bit, %3 : !quantum.bit) %cst = llvm.mlir.constant (6.000000e-01 : f64) : f64 %cst_0 = llvm.mlir.constant (9.000000e-01 : f64) : f64 %cst_1 = llvm.mlir.constant (3.000000e-01 : f64) : f64 - // expected-error@+1 {{number of controlling qubits in input (2) and controlling values (1) must be the same}} + // expected-error@+1 {{number of operands and types do not match}} %out_qubits:3 = quantum.custom "Rot"(%cst, %cst_1, %cst_0) %2 ctrls (%3, %3) ctrlvals (%true) : !quantum.bit, !quantum.bit, !quantum.bit return }