From 4a9706446f5c53f357431c7837d96d0de5206507 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Thu, 31 Jul 2025 21:39:10 +0530 Subject: [PATCH 01/11] Refactor: move hardcoded error strings in mul_leftright to throws.jl for consistency --- src/mul_leftright.jl | 5 +++-- src/throws.jl | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mul_leftright.jl b/src/mul_leftright.jl index 31ef37e83..efb669fc2 100644 --- a/src/mul_leftright.jl +++ b/src/mul_leftright.jl @@ -1,6 +1,7 @@ # using LoopVectorization using HostCPUFeatures: pick_vector_width import SIMD +include("throws.jl") """Nonvectorized version of `mul_left!` used for unit tests.""" function _mul_left_nonvec!(r::AbstractVector{T}, l::AbstractVector{T}; phases::Bool=true) where T<:Unsigned @@ -135,14 +136,14 @@ end ############################## @inline function mul_left!(r::PauliOperator, l::PauliOperator; phases::Val{B}=Val(true)) where B - nqubits(l)==nqubits(r) || throw(DimensionMismatch("The two Pauli operators should have the same length!")) # TODO skip this when @inbounds is set + nqubits(l)==nqubits(r) || throw(DimensionMismatch(THROW_NQUBITS)) # TODO skip this when @inbounds is set s = mul_left!(r.xz, l.xz, phases=phases) B && (r.phase[] = (s+r.phase[]+l.phase[])&0x3) r end @inline function mul_right!(l::PauliOperator, r::PauliOperator; phases::Val{B}=Val(true)) where B - nqubits(l)==nqubits(r) || throw(DimensionMismatch("The two Pauli operators should have the same length!")) # TODO skip this when @inbounds is set + nqubits(l)==nqubits(r) || throw(DimensionMismatch(THROW_NQUBITS)) # TODO skip this when @inbounds is set s = mul_right!(l.xz, r.xz, phases=phases) B && (l.phase[] = (s+r.phase[]+l.phase[])&0x3) l diff --git a/src/throws.jl b/src/throws.jl index 1adc43b29..6cb541010 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -10,3 +10,4 @@ between the pertinent size(s) of the provided arguments." const THROW_NQUBITS = "Unable to perform the requested operation due to encountering a mismatch \ between the number of qubits in the provided arguments." + From 73fdee9a5532a422a4ddf7a7fb266231675fde97 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Fri, 1 Aug 2025 16:22:58 +0530 Subject: [PATCH 02/11] Refactor: move hardcoded error strings in QuantumCliffordHeckeExt to throws.jl for consistency --- .../QuantumCliffordHeckeExt.jl | 1 + ext/QuantumCliffordHeckeExt/lacross.jl | 2 +- ext/QuantumCliffordHeckeExt/lifted_product.jl | 6 +++--- src/throws.jl | 11 +++++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl b/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl index 9a435105d..275a21a2c 100644 --- a/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl +++ b/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl @@ -31,5 +31,6 @@ include("types.jl") include("lifted.jl") include("lacross.jl") include("lifted_product.jl") +include("../../src/throws.jl") end # module diff --git a/ext/QuantumCliffordHeckeExt/lacross.jl b/ext/QuantumCliffordHeckeExt/lacross.jl index 378572457..a9003a906 100644 --- a/ext/QuantumCliffordHeckeExt/lacross.jl +++ b/ext/QuantumCliffordHeckeExt/lacross.jl @@ -142,7 +142,7 @@ struct LaCross <: AbstractCSSCode """A flag indicating whether to use the full-rank rectangular matrix (`true`) or the original circulant matrix (`false`).""" full_rank::Bool function LaCross(n, h, full_rank) - n <= 0 && throw(ArgumentError("Block length must be positive.")) + n <= 0 && throw(ArgumentError(THROW_REQUIRED_POSITIVE_ARG)) new(n, h, full_rank) end end diff --git a/ext/QuantumCliffordHeckeExt/lifted_product.jl b/ext/QuantumCliffordHeckeExt/lifted_product.jl index 4a1a1bc99..440b7ad3e 100644 --- a/ext/QuantumCliffordHeckeExt/lifted_product.jl +++ b/ext/QuantumCliffordHeckeExt/lifted_product.jl @@ -164,7 +164,7 @@ struct LPCode <: AbstractECC repr::Union{Function,Nothing}=nothing ) if repr !== nothing # override the default A_repr/B_repr (exists for backward compat) - is_commutative(GA) || throw(ArgumentError("The group algebra must be commutative when using a single `repr` function, which is not the case here. Please specify separate `A_repr` and `B_repr` instead of a single `repr`. The default choice of `A_repr=right_repr_matrix, B_repr=left_repr_matrix` is frequently sufficient.")) + is_commutative(GA) || throw(ArgumentError(THROW_REPR_NEEDS_COMMUTATIVE_ALGEBRA)) A_repr = B_repr = repr end all(elem.parent == GA for elem in A) && all(elem.parent == GA for elem in B) || error("The base rings of all elements in both matrices must be the same as the group algebra") @@ -181,7 +181,7 @@ struct LPCode <: AbstractECC repr::Union{Function,Nothing}=nothing ) if repr !== nothing # override the default A_repr/B_repr (exists for backward compat) - is_commutative(GA) || throw(ArgumentError("The group algebra must be commutative when using a single `repr` function, which is not the case here. Please specify separate `A_repr` and `B_repr` instead of a single `repr`. The default choice of `A_repr=right_repr_matrix, B_repr=left_repr_matrix` is frequently sufficient.")) + is_commutative(GA) || throw(ArgumentError(THROW_REPR_NEEDS_COMMUTATIVE_ALGEBRA)) A_repr = B_repr = repr end # We are using the representation function of each lifted code. @@ -548,7 +548,7 @@ See also: [`bicycle_codes`](@ref), [`generalized_bicycle_codes`](@ref), [`two_bl [`honeycomb_color_codes`](@ref). """ function honeycomb_color_codes(ℓ::Int, m::Int) - (ℓ % 3 == 0 && m % 3 == 0) || throw(ArgumentError("Both ℓ and m must be divisible by 3")) + (ℓ % 3 == 0 && m % 3 == 0) || throw(ArgumentError(THROW_MUST_BE_DIVISIBLE_BY_3)) GA = group_algebra(GF(2), abelian_group([ℓ, m])) x, y = gens(GA) c = 1 + x + x*y diff --git a/src/throws.jl b/src/throws.jl index 6cb541010..ae5582dd0 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -11,3 +11,14 @@ const THROW_NQUBITS = "Unable to perform the requested operation due to encountering a mismatch \ between the number of qubits in the provided arguments." +const THROW_REPR_NEEDS_COMMUTATIVE_ALGEBRA = +"The group algebra must be commutative when using a single `repr` function,\ +which is not the case here. Please specify separate `A_repr` and `B_repr` \ +instead of a single `repr`. The default choice of\ +`A_repr=right_repr_matrix, B_repr=left_repr_matrix` is frequently sufficient." + +const THROW_MUST_BE_DIVISIBLE_BY_3 = +"The input parameters must be divisible by 3" + +const THROW_REQUIRED_POSITIVE_ARG = +"The input parameter should be positive" \ No newline at end of file From 343fb68644c0be2e9fe5521ba24f4d278be9fb04 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Fri, 1 Aug 2025 17:01:13 +0530 Subject: [PATCH 03/11] Refactor: move hardcoded error strings in QuantumCliffordMakieExt to throws.jl for consistency --- ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl | 3 ++- src/throws.jl | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl b/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl index cceebc62b..30912329a 100644 --- a/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl +++ b/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl @@ -3,6 +3,7 @@ module QuantumCliffordMakieExt using Makie using QuantumClifford import QuantumClifford: stabilizerplot, stabilizerplot_axis +include("../../src/throws.jl") # If you want to directly use heatmap function Makie.convert_arguments(P::Type{<:Makie.Heatmap}, s::Stabilizer) @@ -38,7 +39,7 @@ function Makie.plot!(myplot::StabilizerPlot) h = QuantumClifford.stab_to_gf2(s) h[:,1:end÷2] + h[:,end÷2+1:end]*2 else - throw(ErrorException("`xzcomponents` should be `:split` or `:together`")) + throw(ErrorException(THROW_INVALID_XZ_COMPONENTS)) end r = r[end:-1:1,:]' hm = Makie.heatmap!(myplot, r; diff --git a/src/throws.jl b/src/throws.jl index ae5582dd0..c8556df49 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -21,4 +21,7 @@ const THROW_MUST_BE_DIVISIBLE_BY_3 = "The input parameters must be divisible by 3" const THROW_REQUIRED_POSITIVE_ARG = -"The input parameter should be positive" \ No newline at end of file +"The input parameter should be positive" + +const THROW_INVALID_XZ_COMPONENTS = +"`xzcomponents` should be `:split` or `:together`" \ No newline at end of file From 2422fa68ebfd57f1a245a69c7fc5c4417fe56972 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Fri, 1 Aug 2025 17:21:07 +0530 Subject: [PATCH 04/11] Refactor: move hardcoded error strings in QuantumCliffordOscarExt to throws.jl for consistency --- .../QuantumCliffordOscarExt.jl | 1 + ext/QuantumCliffordOscarExt/d_dimensional_codes.jl | 8 ++++---- src/throws.jl | 14 +++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl b/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl index 7cedbcf7d..4f68c80bb 100644 --- a/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl +++ b/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl @@ -31,5 +31,6 @@ include("types.jl") include("direct_product.jl") include("group_presentation.jl") include("d_dimensional_codes.jl") +include("../../src/throws.jl") end # module diff --git a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl index 4fcc4bc3b..f0442c2a2 100644 --- a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl +++ b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl @@ -376,7 +376,7 @@ struct DDimensionalSurfaceCode <: DDimensionalCode L::Int function DDimensionalSurfaceCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError("Dimension of the Surface code must be at least 2 (got D=$D).")) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION(D))) new(D, L) end end @@ -512,7 +512,7 @@ struct DDimensionalToricCode <: DDimensionalCode L::Int function DDimensionalToricCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError("Dimension of the Toric code must be at least 2 (got D=$D).")) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION(D))) new(D, L) end end @@ -609,12 +609,12 @@ function code_k(c::DDimensionalCode) end function metacheck_matrix_x(c::DDimensionalCode) - c.D ≥ 4 || throw(ArgumentError("`X`-metachecks (`Mx`) require `D ≥ 4` (D=$(c.D))")) + c.D ≥ 4 || throw(ArgumentError(THROW_INVALID_X_METACHECKS(c.D))) return Matrix(boundary_maps(c)[4]) # Mx end function metacheck_matrix_z(c::DDimensionalCode) - c.D ≥ 3 || throw(ArgumentError("`Z`-metachecks (`Mz`) require `D ≥ 3` (D=$(c.D))")) + c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS(c.D)))) return Matrix(boundary_maps(c)[1]') # Mz end diff --git a/src/throws.jl b/src/throws.jl index c8556df49..3b619addf 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -24,4 +24,16 @@ const THROW_REQUIRED_POSITIVE_ARG = "The input parameter should be positive" const THROW_INVALID_XZ_COMPONENTS = -"`xzcomponents` should be `:split` or `:together`" \ No newline at end of file +"`xzcomponents` should be `:split` or `:together`" + +function THROW_INVALID_CODE_DIMENSION(D) + return "Dimension of the input code must be at least 2 (got D = $D)." +end + +function THROW_INVALID_X_METACHECKS(D) + return "`X`-metachecks (`Mx`) require `D ≥ 4` (D=$(D))" +end + +function THROW_INVALID_Z_METACHECKS(D) + return "`Z`-metachecks (`Mz`) require `D ≥ 3` (D=$(D))" +end \ No newline at end of file From ef6e53318c075d3656238f62c42a0078390b589c Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Fri, 1 Aug 2025 23:39:42 +0530 Subject: [PATCH 05/11] Refactor: move hardcoded error strings in the rest of external modules to throws.jl --- ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl | 1 + ext/QuantumCliffordGPUExt/utils.jl | 2 +- .../QuantumCliffordJuMPExt.jl | 1 + .../min_distance_mixed_integer_programming.jl | 8 ++++---- ext/QuantumCliffordOscarExt/d_dimensional_codes.jl | 2 +- .../QuantumCliffordPlotsExt.jl | 3 ++- src/throws.jl | 14 +++++++++++++- 7 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl b/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl index 484b2f452..b1faca4bc 100644 --- a/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl +++ b/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl @@ -11,5 +11,6 @@ include("apply.jl") include("pauli_frames.jl") include("fastmemlayout.jl") include("apply_noise.jl") +include("../../src/throws.jl") end diff --git a/ext/QuantumCliffordGPUExt/utils.jl b/ext/QuantumCliffordGPUExt/utils.jl index cbfed8408..c26c637f6 100644 --- a/ext/QuantumCliffordGPUExt/utils.jl +++ b/ext/QuantumCliffordGPUExt/utils.jl @@ -1,6 +1,6 @@ macro run_cuda(call, ndrange) # destructure the kernel call - Meta.isexpr(call, :call) || throw(ArgumentError("first argument to @run_cuda should be a function call")) + Meta.isexpr(call, :call) || throw(ArgumentError(THROW_INVALID_CUDA_ARG)) f = call.args[1] args = call.args[2:end] args = [esc(x) for x in args] diff --git a/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl b/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl index e3c8ecda1..3e7206e18 100644 --- a/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl +++ b/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl @@ -24,5 +24,6 @@ import ILog2: ilog2, RoundUp export distance include("min_distance_mixed_integer_programming.jl") +include("../../src/throws.jl") end diff --git a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl index ec81eea4b..58e124b91 100644 --- a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl +++ b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl @@ -158,7 +158,7 @@ are as follows: """ function distance(code::AbstractECC, alg::DistanceMIPAlgorithm) logical_qubits = isnothing(alg.logical_qubit) ? (1:code_k(code)) : (alg.logical_qubit:alg.logical_qubit) - isnothing(alg.logical_qubit) || (1 <= alg.logical_qubit <= code_k(code)) || throw(ArgumentError("Logical qubit out of range")) + isnothing(alg.logical_qubit) || (1 <= alg.logical_qubit <= code_k(code)) || throw(ArgumentError(THROW_BOUNDS)) # Get the appropriate logical operators and matrices based on operator type logical_operator_type = alg.logical_operator_type l, H, h = if logical_operator_type == :X @@ -254,11 +254,11 @@ function _minimum_distance(hx, lx, opt, opt_summary, time_limit) # Ensure the model is solved and feasible if !is_solved_and_feasible(model) if termination_status(model) == MOI.MEMORY_LIMIT - throw(ErrorException("Model exceeded memory limits")) + throw(ErrorException(THROW_MODEL_MEMORY_LIMIT)) elseif termination_status(model) == MOI.TIME_LIMIT - throw(ErrorException("Model exceeded time limit")) + throw(ErrorException(THROW_MODEL_TIME_LIMIT)) else - throw(ErrorException("Model failed to solve: $(termination_status(model))")) + throw(ErrorException(THROW_MODEL_FAILED(termination_status(model)))) end end opt_val = sum(value(x[i]) for i in 1:n) diff --git a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl index f0442c2a2..e7d057fe5 100644 --- a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl +++ b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl @@ -614,7 +614,7 @@ function metacheck_matrix_x(c::DDimensionalCode) end function metacheck_matrix_z(c::DDimensionalCode) - c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS(c.D)))) + c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS(c.D))) return Matrix(boundary_maps(c)[1]') # Mz end diff --git a/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl b/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl index a7af4958c..7487af6d2 100644 --- a/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl +++ b/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl @@ -2,6 +2,7 @@ module QuantumCliffordPlotsExt using Plots using QuantumClifford +include("../../src/throws.jl") @recipe function f(s::QuantumClifford.Stabilizer; xzcomponents=:together) seriestype := :heatmap @@ -21,7 +22,7 @@ using QuantumClifford h = QuantumClifford.stab_to_gf2(s) h[:,1:end÷2] + h[:,end÷2+1:end]*2 else - throw(ErrorException("`xzcomponents` should be `:split` or `:together`")) + throw(ErrorException(THROW_INVALID_XZ_COMPONENTS)) end end diff --git a/src/throws.jl b/src/throws.jl index 3b619addf..2b6bef314 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -36,4 +36,16 @@ end function THROW_INVALID_Z_METACHECKS(D) return "`Z`-metachecks (`Mz`) require `D ≥ 3` (D=$(D))" -end \ No newline at end of file +end + +const THROW_INVALID_CUDA_ARG = +"First argument to @run_cuda should be a function call" + +const THROW_MODEL_MEMORY_LIMIT = +"Model exceeded memory limits" + +const THROW_MODEL_TIME_LIMIT = +"Model exceeded time limit" + +function THROW_MODEL_FAILED(error) + return "Model failed to solve: $error" From 1eb0bc72afa652427db2c88142236e6671657754 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Sat, 2 Aug 2025 00:08:26 +0530 Subject: [PATCH 06/11] refactor: remove functions from throws.jl --- .../min_distance_mixed_integer_programming.jl | 2 +- .../d_dimensional_codes.jl | 8 ++++---- src/throws.jl | 19 +++++++------------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl index 58e124b91..430e58ecb 100644 --- a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl +++ b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl @@ -258,7 +258,7 @@ function _minimum_distance(hx, lx, opt, opt_summary, time_limit) elseif termination_status(model) == MOI.TIME_LIMIT throw(ErrorException(THROW_MODEL_TIME_LIMIT)) else - throw(ErrorException(THROW_MODEL_FAILED(termination_status(model)))) + throw(ErrorException("Model failed to solve :$(termination_status(model))")) end end opt_val = sum(value(x[i]) for i in 1:n) diff --git a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl index e7d057fe5..cb50212bc 100644 --- a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl +++ b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl @@ -376,7 +376,7 @@ struct DDimensionalSurfaceCode <: DDimensionalCode L::Int function DDimensionalSurfaceCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION(D))) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION)) new(D, L) end end @@ -512,7 +512,7 @@ struct DDimensionalToricCode <: DDimensionalCode L::Int function DDimensionalToricCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION(D))) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION)) new(D, L) end end @@ -609,12 +609,12 @@ function code_k(c::DDimensionalCode) end function metacheck_matrix_x(c::DDimensionalCode) - c.D ≥ 4 || throw(ArgumentError(THROW_INVALID_X_METACHECKS(c.D))) + c.D ≥ 4 || throw(ArgumentError(THROW_INVALID_X_METACHECKS)) return Matrix(boundary_maps(c)[4]) # Mx end function metacheck_matrix_z(c::DDimensionalCode) - c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS(c.D))) + c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS)) return Matrix(boundary_maps(c)[1]') # Mz end diff --git a/src/throws.jl b/src/throws.jl index 2b6bef314..576716210 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -26,17 +26,15 @@ const THROW_REQUIRED_POSITIVE_ARG = const THROW_INVALID_XZ_COMPONENTS = "`xzcomponents` should be `:split` or `:together`" -function THROW_INVALID_CODE_DIMENSION(D) - return "Dimension of the input code must be at least 2 (got D = $D)." -end +const THROW_INVALID_CODE_DIMENSION = +"Dimension of the input code must be at least 2" -function THROW_INVALID_X_METACHECKS(D) - return "`X`-metachecks (`Mx`) require `D ≥ 4` (D=$(D))" -end +const THROW_INVALID_X_METACHECKS = +"`X`-metachecks (`Mx`) require `D ≥ 4`" + +const THROW_INVALID_Z_METACHECKS = +"`Z`-metachecks (`Mz`) require `D ≥ 3`" -function THROW_INVALID_Z_METACHECKS(D) - return "`Z`-metachecks (`Mz`) require `D ≥ 3` (D=$(D))" -end const THROW_INVALID_CUDA_ARG = "First argument to @run_cuda should be a function call" @@ -46,6 +44,3 @@ const THROW_MODEL_MEMORY_LIMIT = const THROW_MODEL_TIME_LIMIT = "Model exceeded time limit" - -function THROW_MODEL_FAILED(error) - return "Model failed to solve: $error" From 82c685b2f1131180ad05ac4d39e81cf8f17e7f1e Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Thu, 7 Aug 2025 17:56:52 +0530 Subject: [PATCH 07/11] refactor: move hardcoded error strings in lib/QECCore/classical codes to throws.jl --- lib/QECCore/src/QECCore.jl | 2 ++ lib/QECCore/src/codes/classical/golay.jl | 2 +- lib/QECCore/src/codes/classical/hamming.jl | 2 +- lib/QECCore/src/codes/classical/recursivereedmuller.jl | 2 +- lib/QECCore/src/codes/classical/reedmuller.jl | 2 +- src/throws.jl | 9 +++++++++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/QECCore/src/QECCore.jl b/lib/QECCore/src/QECCore.jl index 57fcd69f4..79f257dbe 100644 --- a/lib/QECCore/src/QECCore.jl +++ b/lib/QECCore/src/QECCore.jl @@ -58,6 +58,8 @@ include("codes/quantum/delfosse_reichardt_code.jl") include("codes/quantum/delfosse_reichardt_repcode.jl") include("codes/quantum/delfosse_reichardt_823_code.jl") +include("../../../src/throws.jl") + function __init__() if isdefined(Base.Experimental, :register_error_hint) Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs diff --git a/lib/QECCore/src/codes/classical/golay.jl b/lib/QECCore/src/codes/classical/golay.jl index ffed3d8f6..8b7952fa9 100644 --- a/lib/QECCore/src/codes/classical/golay.jl +++ b/lib/QECCore/src/codes/classical/golay.jl @@ -31,7 +31,7 @@ struct Golay <: AbstractCECC function Golay(n) if !(n in (23, 24)) - throw(ArgumentError("Invalid parameters: `n` must be either 24 or 23 to obtain a valid code.")) + throw(ArgumentError(THROW_INVALID_PARAMETERS_GOLAY)) end new(n) end diff --git a/lib/QECCore/src/codes/classical/hamming.jl b/lib/QECCore/src/codes/classical/hamming.jl index 4947577fe..99abb3860 100644 --- a/lib/QECCore/src/codes/classical/hamming.jl +++ b/lib/QECCore/src/codes/classical/hamming.jl @@ -22,7 +22,7 @@ struct Hamming <: AbstractCECC r::Int function Hamming(r) if r < 2 - throw(ArgumentError("Invalid parameters: `r` must be ≥ 2 to obtain a valid code.")) + throw(ArgumentError(THROW_INVALID_PARAMETERS_HAMMING)) end new(r) end diff --git a/lib/QECCore/src/codes/classical/recursivereedmuller.jl b/lib/QECCore/src/codes/classical/recursivereedmuller.jl index 15b3667a0..6b81fd965 100644 --- a/lib/QECCore/src/codes/classical/recursivereedmuller.jl +++ b/lib/QECCore/src/codes/classical/recursivereedmuller.jl @@ -33,7 +33,7 @@ struct RecursiveReedMuller <: AbstractCECC function RecursiveReedMuller(r, m) if r < 0 || r > m - throw(ArgumentError("Invalid parameters: r must be non-negative and r ≤ m in order to valid code.")) + throw(ArgumentError(THROW_INVALID_PARAMETERS_REEDMULLER)) end new(r, m) end diff --git a/lib/QECCore/src/codes/classical/reedmuller.jl b/lib/QECCore/src/codes/classical/reedmuller.jl index bb019ee8f..0df393099 100644 --- a/lib/QECCore/src/codes/classical/reedmuller.jl +++ b/lib/QECCore/src/codes/classical/reedmuller.jl @@ -28,7 +28,7 @@ struct ReedMuller <: AbstractCECC function ReedMuller(r, m) if r < 0 || r > m - throw(ArgumentError("Invalid parameters: r must be non-negative and r ≤ m in order to valid code.")) + throw(ArgumentError(THROW_INVALID_PARAMETERS_REEDMULLER)) end new(r, m) end diff --git a/src/throws.jl b/src/throws.jl index 576716210..28335e202 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -44,3 +44,12 @@ const THROW_MODEL_MEMORY_LIMIT = const THROW_MODEL_TIME_LIMIT = "Model exceeded time limit" + +const THROW_INVALID_PARAMETERS_GOLAY = +"Invalid parameters: `n` must be either 24 or 23 to obtain a valid code." + +const THROW_INVALID_PARAMETERS_HAMMING = +"Invalid parameters: `r` must be ≥ 2 to obtain a valid code." + +const THROW_INVALID_PARAMETERS_REEDMULLER = +"Invalid parameters: r must be non-negative and r ≤ m in order to valid code." From 9d06a1faec03f346fe96a0a98786c75648d70f22 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Thu, 7 Aug 2025 18:18:15 +0530 Subject: [PATCH 08/11] refactor: move hardcoded error strings in lib/QECCore/quantum codes to throws.jl --- lib/QECCore/src/codes/quantum/color_codes.jl | 8 +++--- .../quantum/delfosse_reichardt_823_code.jl | 2 +- .../codes/quantum/delfosse_reichardt_code.jl | 8 +++--- .../quantum/delfosse_reichardt_repcode.jl | 4 +-- .../src/codes/quantum/quantumreedmuller.jl | 2 +- .../quantum/quantumtannergraphproduct.jl | 2 +- lib/QECCore/src/codes/quantum/tillichzemor.jl | 4 +-- src/throws.jl | 26 +++++++++++++++++++ 8 files changed, 40 insertions(+), 16 deletions(-) diff --git a/lib/QECCore/src/codes/quantum/color_codes.jl b/lib/QECCore/src/codes/quantum/color_codes.jl index 79d69dea5..f74e12444 100644 --- a/lib/QECCore/src/codes/quantum/color_codes.jl +++ b/lib/QECCore/src/codes/quantum/color_codes.jl @@ -52,9 +52,9 @@ struct Triangular488 <: TriangularCode function Triangular488(d) if d%2!=1 - throw(ArgumentError("Only odd distance triangular color codes are allowed.\nRefer to https://arxiv.org/abs/1108.5738")) + throw(ArgumentError(THROW_COLOR_CODES_ODD)) elseif d<3 - throw(ArgumentError("Smallest allowed distance is 3.\nRefer to https://arxiv.org/abs/1108.5738")) + throw(ArgumentError(THROW_COLOR_CODES_MIN_DIST)) end return new(d) end @@ -110,9 +110,9 @@ struct Triangular666 <: TriangularCode d::Int function Triangular666(d) if d%2!=1 - throw(ArgumentError("Only odd distance triangular color codes are allowed.\nRefer to https://arxiv.org/abs/1108.5738")) + throw(ArgumentError(THROW_COLOR_CODES_ODD)) elseif d<3 - throw(ArgumentError("Smallest allowed distance is 3.\nRefer to https://arxiv.org/abs/1108.5738")) + throw(ArgumentError(THROW_COLOR_CODES_MIN_DIST)) end return new(d) end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl index cd840a889..0b49a9103 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl @@ -56,7 +56,7 @@ struct DelfosseReichardt823 <: AbstractQECC """The number of blocks in the Delfosse-Reichardt generalized [[8, 2, 3]] code.""" p::Int function DelfosseReichardt823(p) - p < 1 && throw(ArgumentError("The number of blocks must be at least 1 to construct a valid code.")) + p < 1 && throw(ArgumentError(THROW_DELFOSSE_823_MIN_BLOCKS)) new(p) end end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl index 43f632e28..a647d6962 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl @@ -86,14 +86,12 @@ struct DelfosseReichardt <: AbstractCSSCode """The log-length of the classical Reed-Muller code.""" m::Int function DelfosseReichardt(p,r,m) - p < 2 && throw(ArgumentError("The number of blocks must be at least 2 to construct a valid code.")) + p < 2 && throw(ArgumentError(THROW_DELFOSSE_MIN_BLOCKS)) if r < 0 || r > m - throw(ArgumentError("Invalid parameters: r must be non-negative and r ≤ m in order to valid code.")) + throw(ArgumentError(THROW_INVALID_PARAMETERS_REEDMULLER)) end if !iszero(mod.(parity_matrix(ReedMuller(r,m))*parity_matrix(ReedMuller(r,m))',2)) - throw(ArgumentError("The `Reed-Muller` parity check matrix must be 'self-orthogonal' to construct a self-dual - CSS `DelfosseReichardt` code. Use `search_self_orthogonal_rm_codes` to search for good parameters for `Reed-Muller` codes - that provide `self-orthogonal` seeds.")) + throw(ArgumentError(THROW_DELFOSSE_SELF_ORTHOGONAL)) end new(p,r,m) end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl index 32c5e1d3e..e1d60fc9b 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl @@ -57,8 +57,8 @@ struct DelfosseReichardtRepCode <: AbstractCSSCode """The number of blocks in the Delfosse-Reichardt Repetition code.""" p::Int function DelfosseReichardtRepCode(p) - p < 2 && throw(ArgumentError("The number of blocks must be at least 2 to construct a valid code.")) - p % 2 != 0 && throw(ArgumentError("The number of blocks must be a multiple of 2.")) + p < 2 && throw(ArgumentError(THROW_DELFOSSE_MIN_BLOCKS)) + p % 2 != 0 && throw(ArgumentError(THROW_DELFOSSE_REP_MULTIPLE)) new(p) end end diff --git a/lib/QECCore/src/codes/quantum/quantumreedmuller.jl b/lib/QECCore/src/codes/quantum/quantumreedmuller.jl index 2039bd72d..b7d6b24cb 100644 --- a/lib/QECCore/src/codes/quantum/quantumreedmuller.jl +++ b/lib/QECCore/src/codes/quantum/quantumreedmuller.jl @@ -21,7 +21,7 @@ struct QuantumReedMuller <: AbstractCSSCode m::Int function QuantumReedMuller(m) if m < 3 - throw(DomainError("Invalid parameters: m must be bigger than 2 in order to have a valid code.")) + throw(DomainError(THROW_INVALID_QUANTUM_REED_MULLER)) end new(m) end diff --git a/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl b/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl index 9bb9bc6de..9714e329c 100644 --- a/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl +++ b/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl @@ -203,7 +203,7 @@ julia> code_n(c), code_k(c) struct CyclicQuantumTannerGraphProduct <: AbstractCSSCode m::Int function CyclicQuantumTannerGraphProduct(m::Int) - m > 0 || throw(ArgumentError("m must be positive.")) + m > 0 || throw(ArgumentError(THROW_REQUIRED_POSITIVE_ARG)) new(m) end end diff --git a/lib/QECCore/src/codes/quantum/tillichzemor.jl b/lib/QECCore/src/codes/quantum/tillichzemor.jl index 9cf175ca8..de12d7bec 100644 --- a/lib/QECCore/src/codes/quantum/tillichzemor.jl +++ b/lib/QECCore/src/codes/quantum/tillichzemor.jl @@ -138,7 +138,7 @@ struct TillichZemor{M} <: AbstractCSSCode where {M <: Union{Nothing,Tuple{Abstra matrices::M function TillichZemor(n::Int, m::Int, r::Int, matrices::M=nothing) where {M <: Union{Nothing,Tuple{AbstractMatrix,AbstractMatrix}}} - (m ≥ r && (n - m)*r ≥ m) || throw(ArgumentError(("Conditions for the existence of `M` in `H = [C | M]` are not satisfied."))) + (m ≥ r && (n - m)*r ≥ m) || throw(ArgumentError((THROW_INVALID_PARAMETERS_TILLICH_ZEMOR))) new{M}(n, m, r, matrices) end end @@ -202,7 +202,7 @@ function _create_matrix_M_random(rng::AbstractRNG, m::Int, n::Int, r::Int) end function _construct_parity_check_matrix(rng::AbstractRNG, n::Int, m::Int, r::Int) - (m ≥ r && (n - m)*r ≥ m) || throw(ArgumentError(("Conditions for the existence of `M` in `H = [C | M]` are not satisfied."))) + (m ≥ r && (n - m)*r ≥ m) || throw(ArgumentError((THROW_INVALID_PARAMETERS_TILLICH_ZEMOR))) C = _create_circulant_matrix(m) M = _create_matrix_M_random(rng, m, n, r) # The parity-check matrix H = [C | M] diff --git a/src/throws.jl b/src/throws.jl index 28335e202..b0be154c7 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -53,3 +53,29 @@ const THROW_INVALID_PARAMETERS_HAMMING = const THROW_INVALID_PARAMETERS_REEDMULLER = "Invalid parameters: r must be non-negative and r ≤ m in order to valid code." + +const THROW_COLOR_CODES_ODD = +"Only odd distance triangular color codes are allowed.\nRefer to https://arxiv.org/abs/1108.5738" + +const THROW_COLOR_CODES_MIN_DIST = +"Smallest allowed distance is 3.\nRefer to https://arxiv.org/abs/1108.5738" + +const THROW_DELFOSSE_823_MIN_BLOCKS = +"The number of blocks must be at least 1 to construct a valid code." + +const THROW_DELFOSSE_MIN_BLOCKS = +"The number of blocks must be at least 2 to construct a valid code." + +const THROW_DELFOSSE_SELF_ORTHOGONAL = +"The `Reed-Muller` parity check matrix must be 'self-orthogonal' to construct a self-dual +CSS `DelfosseReichardt` code. Use `search_self_orthogonal_rm_codes` to search for good parameters for `Reed-Muller` codes +that provide `self-orthogonal` seeds." + +const THROW_DELFOSSE_REP_MULTIPLE = +"The number of blocks must be a multiple of 2." + +const THROW_INVALID_QUANTUM_REED_MULLER = +"Invalid parameters: m must be bigger than 2 in order to have a valid code." + +const THROW_INVALID_PARAMETERS_TILLICH_ZEMOR = +"Conditions for the existence of `M` in `H = [C | M]` are not satisfied." \ No newline at end of file From e8c5fc0b519167eb650beb4a47f92e6ba569a184 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Sat, 9 Aug 2025 05:51:00 +0530 Subject: [PATCH 09/11] refactor: move hardcoded strings in the rest of the files to throws.jl --- src/QuantumClifford.jl | 17 ++--- src/dense_cliffords.jl | 7 +- src/ecc/ECC.jl | 7 +- src/ecc/codes/classical/bch.jl | 6 +- src/ecc/codes/classical/lifted.jl | 2 +- src/ecc/codes/d_dimensional_codes.jl | 4 +- src/ecc/codes/lifted_product.jl | 4 +- src/ecc/decoder_pipeline.jl | 22 +++--- src/entanglement.jl | 2 +- src/grouptableaux.jl | 3 +- src/linalg.jl | 9 ++- src/misc_ops.jl | 8 +- src/nonclifford.jl | 17 ++--- src/project_trace_reset.jl | 15 ++-- src/symbolic_cliffords.jl | 32 ++++---- src/throws.jl | 109 ++++++++++++++++++++++++++- src/useful_states.jl | 3 +- 17 files changed, 186 insertions(+), 81 deletions(-) diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index a2d22fb07..d112f82d0 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -133,9 +133,7 @@ function __init__() end end -include("throws.jl") -const NoZeroQubit = ArgumentError("Qubit indices have to be larger than zero, but you are attempting to create a gate acting on a qubit with a non-positive index. Ensure indexing always starts from 1.") # Predefined constants representing the permitted phases encoded # in the low bits of UInt8. @@ -189,7 +187,7 @@ function Tableau(phases::AbstractVector{<: Unsigned}, xs::AbstractMatrix{Bool}, r_xs = size(xs, 1) r_zs = size(zs, 1) if length(phases) != r_xs || r_xs != r_zs - throw(DimensionMismatch(lazy"The length of phases ($(length(phases))), rows of xs ($r_xs), rows of zs ($r_zs) must all be equal.")) + throw(DimensionMismatch(THROW_SIZE)) end Tableau( phases,size(xs, 2), @@ -656,7 +654,7 @@ function MixedDestabilizer(d::Destabilizer, r::Int) if l==2n MixedDestabilizer(tab(d), r) else - throw(DomainError("Only full-rank `Destabilizer` can be converted to `MixedDestabilizer` with specific rank. Try not specifying `r`.")) + throw(DomainError(THROW_ONLY_FULL_RANK_DESTABILIZER_SUPPORTED)) end end function MixedDestabilizer(d::Destabilizer) @@ -833,8 +831,8 @@ comm(l::Tableau, r::PauliOperator) = comm(r, l) """An in-place version of [`comm`](@ref), storing its output in the given buffer.""" function comm! end function comm!(v, l::PauliOperator, r::Tableau) - length(v) == length(r) || throw(DimensionMismatch(lazy"The dimensions of the output buffer and the input tableau have to match in `comm!`")) - nqubits(l) == nqubits(r) || throw(DimensionMismatch(lazy"The number of qubits of the input Pauli operator and the input tableau have to match in `comm!`")) + length(v) == length(r) || throw(DimensionMismatch(THROW_SIZE)) + nqubits(l) == nqubits(r) || throw(DimensionMismatch(THROW_NQUBITS)) for i in 1:length(r) v[i] = comm(l,r,i) end @@ -872,7 +870,7 @@ function Base.:(*)(l::Number, r::PauliOperator) elseif l==-1im p.phase[] = (p.phase[] + 3)&0x3 else - throw(DomainError(l,"Only {±1,±i} are permitted as phases.")) + throw(DomainError(l,THROW_PHASES)) end p end @@ -1059,7 +1057,7 @@ function Base.hcat(tabs::Tableau...) # TODO this implementation is slow as it un for tab in tabs rows_tab, cols_tab = size(tab) if rows_tab != rows - throw(ArgumentError("All input Tableaux/Stabilizers must have the same number of rows.")) + throw(ArgumentError(THROW_ROW_MISMATCH_TABLEAUX)) end for i in 1:rows for j in 1:cols_tab @@ -1099,7 +1097,7 @@ end # TODO no need to track phases outside of stabview function _apply!(stab::AbstractStabilizer, p::PauliOperator; phases::Val{B}=Val(true)) where B - nqubits(stab)==nqubits(p) || throw(DimensionMismatch("The tableau and the Pauli operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error.")) + nqubits(stab)==nqubits(p) || throw(DimensionMismatch(THROW_INVALID_ACTION_QUBITS)) s = tab(stab) B || return stab for i in eachindex(s) @@ -1462,5 +1460,6 @@ include("grouptableaux.jl") include("plotting_extensions.jl") # include("gpu_adapters.jl") +include("throws.jl") end #module diff --git a/src/dense_cliffords.jl b/src/dense_cliffords.jl index d750fda49..31e11d74b 100644 --- a/src/dense_cliffords.jl +++ b/src/dense_cliffords.jl @@ -1,3 +1,4 @@ +include("throws.jl") """ Clifford Operator specified by the mapping of the basis generators. @@ -50,7 +51,7 @@ struct CliffordOperator{T<:Tableau,P<:PauliOperator} <: AbstractCliffordOperator # destab = tab(Destabilizer(stab)) # new{typeof(destab.phases),typeof(destab.xzs)}(destab) # TODO be smarter about type signatures here... there should be a better way else - throw(DimensionMismatch("Input tableau should be of size 2n×n (top half is the X mappings and the bottom half are the Z mappings).")) + throw(DimensionMismatch(THROW_INVALID_PARAMETERS_CLIFFORD)) end end end @@ -113,7 +114,7 @@ end """Nonvectorized version of `apply!` used for unit tests.""" function _apply_nonthread!(stab::AbstractStabilizer, c::CliffordOperator; phases::Bool=true) - nqubits(stab)==nqubits(c) || throw(DimensionMismatch("The tableau and the Clifford operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error.")) + nqubits(stab)==nqubits(c) || throw(DimensionMismatch(THROW_INVALID_ACTION_QUBITS)) s_tab = tab(stab) c_tab = tab(c) new_stabrow = c.buffer @@ -126,7 +127,7 @@ end # TODO no need to track phases outside of stabview function _apply!(stab::AbstractStabilizer, c::CliffordOperator; phases::Val{B}=Val(true)) where B - nqubits(stab)==nqubits(c) || throw(DimensionMismatch("The tableau and the Clifford operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error.")) + nqubits(stab)==nqubits(c) || throw(DimensionMismatch(THROW_INVALID_ACTION_QUBITS)) s_tab = tab(stab) c_tab = tab(c) threadlocal = c.buffer diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index c2f0d1670..0a9c2d5f7 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -54,7 +54,7 @@ Only CSS codes have this method. See also: [`parity_checks`](@ref)""" function parity_matrix_x(code::AbstractECC) - throw(lazy"Codes of type $(typeof(code)) do not have separate X and Z parity checks, either because they are not a CSS code and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library.") + throw(THROW_CHECKS_MISSING) end """Parity check boolean matrix of a code (only the Z entries in the tableau, i.e. the checks for X errors). @@ -63,7 +63,7 @@ Only CSS codes have this method. See also: [`parity_checks`](@ref)""" function parity_matrix_z(code::AbstractECC) - throw(lazy"Codes of type $(typeof(code)) do not have separate X and Z parity checks, either because they are not a CSS code and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library.") + throw(THROW_CHECKS_MISSING) end """Check if the code is CSS. @@ -141,7 +141,7 @@ $FIELDS time_limit::Float64=60.0 function DistanceMIPAlgorithm(logical_qubit, logical_operator_type, solver, opt_summary, time_limit) - logical_operator_type ∈ (:X, :Z) || throw(ArgumentError("`logical_operator_type` must be :X or :Z")) + logical_operator_type ∈ (:X, :Z) || throw(ArgumentError(THROW_INVALID_LOGICAL_OPERATOR)) new(logical_qubit, logical_operator_type, solver, opt_summary, time_limit) end end @@ -390,6 +390,7 @@ function isdegenerate(H::Stabilizer, d::Int=1) return isdegenerate(H, errors) end +include("../throws.jl") include("circuits.jl") include("decoder_pipeline.jl") diff --git a/src/ecc/codes/classical/bch.jl b/src/ecc/codes/classical/bch.jl index 315823e24..7436c060c 100644 --- a/src/ecc/codes/classical/bch.jl +++ b/src/ecc/codes/classical/bch.jl @@ -39,9 +39,9 @@ struct BCH <: AbstractPolynomialCode m::Int t::Int function BCH(m, t) - m < 3 && throw(ArgumentError("m must be greater than or equal to 3")) - t >= 2^(m - 1) && throw(ArgumentError("t must be less than 2ᵐ ⁻ ¹")) - m * t > 2^m - 1 && throw(ArgumentError("m*t must be less than or equal to 2ᵐ - 1")) + if m < 3 || t >= 2^(m - 1) || m * t > 2^m - 1 + throw(ArgumentError(THROW_INVALID_PARAMETERS_BCH_ARG)) + end new(m, t) end end diff --git a/src/ecc/codes/classical/lifted.jl b/src/ecc/codes/classical/lifted.jl index a7c20fa04..3413de76a 100644 --- a/src/ecc/codes/classical/lifted.jl +++ b/src/ecc/codes/classical/lifted.jl @@ -4,7 +4,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LiftedCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw("The `LiftedCode` depends on the package `Hecke` but you have not installed or imported it yet. Immediately after you import `Hecke`, the `LiftedCode` will be available.") + throw(THROW_MISSING_HECKE) end return ext.LiftedCode(args...; kwargs...) end diff --git a/src/ecc/codes/d_dimensional_codes.jl b/src/ecc/codes/d_dimensional_codes.jl index 341aa5fd2..969145133 100644 --- a/src/ecc/codes/d_dimensional_codes.jl +++ b/src/ecc/codes/d_dimensional_codes.jl @@ -7,7 +7,7 @@ Implemented as a package extension with `Oscar`. Check the [QuantumClifford docu function DDimensionalSurfaceCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordOscarExt) if isnothing(ext) - throw("The `DDimensionalSurfaceCode` depends on the package `Oscar` but you have not installed or imported it yet. Immediately after you import `Oscar`, the `DDimensionalSurfaceCode` will be available.") + throw(THROW_MISSING_OSCAR) end return ext.DDimensionalSurfaceCode(args...; kwargs...) end @@ -18,7 +18,7 @@ Implemented as a package extension with `Oscar`. Check the [QuantumClifford docu function DDimensionalToricCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordOscarExt) if isnothing(ext) - throw("The `DDimensionalToricCode` depends on the package `Oscar` but you have not installed or imported it yet. Immediately after you import `Oscar`, the `DDimensionalToricCode` will be available.") + throw(THROW_MISSING_OSCAR) end return ext.DDimensionalToricCode(args...; kwargs...) end diff --git a/src/ecc/codes/lifted_product.jl b/src/ecc/codes/lifted_product.jl index a642d2aa2..76d607e9f 100644 --- a/src/ecc/codes/lifted_product.jl +++ b/src/ecc/codes/lifted_product.jl @@ -4,7 +4,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LPCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw("The `LPCode` depends on the package `Hecke` but you have not installed or imported it yet. Immediately after you import `Hecke`, the `LPCode` will be available.") + throw(THROW_MISSING_HECKE) end return ext.LPCode(args...; kwargs...) end @@ -35,7 +35,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LaCross(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw("The `LaCross` quantum LDPC code depends on the package `Hecke` but you have not installed or imported it yet. Immediately after you import `Hecke`, the `LaCross` will be available.") + throw(THROW_MISSING_HECKE) end return ext.LaCross(args...; kwargs...) end diff --git a/src/ecc/decoder_pipeline.jl b/src/ecc/decoder_pipeline.jl index aeb481851..3d3d852ae 100644 --- a/src/ecc/decoder_pipeline.jl +++ b/src/ecc/decoder_pipeline.jl @@ -14,7 +14,7 @@ function batchdecode(d::AbstractSyndromeDecoder, syndrome_samples) H = parity_checks(d) s, n = size(H) samples, _s = size(syndrome_samples) - s == _s || throw(ArgumentError(lazy"The syndromes given to `batchdecode` have the wrong dimensions. The syndrome length is $(_s) while it should be $(s)")) + s == _s || throw(ArgumentError(THROW_SIZE)) results = falses(samples, 2n) for (i,syndrome_sample) in enumerate(eachrow(syndrome_samples)) guess = decode(d, syndrome_sample)# TODO use `decode!` @@ -38,7 +38,7 @@ See also: [`NaiveSyndromeECCSetup`](@ref), [`ShorSyndromeECCSetup`](@ref)""" struct CommutationCheckECCSetup <: AbstractECCSetup xz_noise::Float64 function CommutationCheckECCSetup(xz_noise) - 0<=xz_noise<=1 || throw(DomainError(xz_noise, "The independent X/Z memory noise in `CommutationCheckECCSetup` should be between 0 and 1.")) + 0<=xz_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) new(xz_noise) end end @@ -53,8 +53,8 @@ struct NaiveSyndromeECCSetup <: AbstractECCSetup mem_noise::Float64 two_qubit_gate_noise::Float64 function NaiveSyndromeECCSetup(mem_noise, two_qubit_gate_noise) - 0<=mem_noise<=1 || throw(DomainError(mem_noise, "The memory noise in `NaiveSyndromeECCSetup` should be between 0 and 1.")) - 0<=two_qubit_gate_noise<=1 || throw(DomainError(two_qubit_gate_noise, "The two-qubit gate noise in `NaiveSyndromeECCSetup` should be between 0 and 1.")) + 0<=mem_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) + 0<=two_qubit_gate_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) new(mem_noise, two_qubit_gate_noise) end end @@ -73,8 +73,8 @@ struct ShorSyndromeECCSetup <: AbstractECCSetup mem_noise::Float64 two_qubit_gate_noise::Float64 function ShorSyndromeECCSetup(mem_noise, two_qubit_gate_noise) - 0<=mem_noise<=1 || throw(DomainError(mem_noise, "The memory noise in `ShorSyndromeECCSetup` should be between 0 and 1.")) - 0<=two_qubit_gate_noise<=1 || throw(DomainError(two_qubit_gate_noise, "The two-qubit gate noise in `ShorSyndromeECCSetup` should be between 0 and 1.")) + 0<=mem_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) + 0<=two_qubit_gate_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) new(mem_noise, two_qubit_gate_noise) end end @@ -273,7 +273,7 @@ end function BeliefPropDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt) if isnothing(ext) - throw("The `BeliefPropDecoder` depends on the package `LDPCDecoders` but you have not installed or imported `LDPCDecoders` yet. Immediately after you import `LDPCDecoders`, the `BeliefPropDecoder` will be available.") + throw(THROW_MISSING_LDPCDecoders) end return ext.BeliefPropDecoder(args...; kwargs...) end @@ -282,7 +282,7 @@ end function BitFlipDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt) if isnothing(ext) - throw("The `BitFlipDecoder` depends on the package `LDPCDecoders` but you have not installed or imported `LDPCDecoders` yet. Immediately after you import `LDPCDecoders`, the `BitFlipDecoder` will be available.") + throw(THROW_MISSING_LDPCDecoders) end return ext.BitFlipDecoder(args...; kwargs...) end @@ -292,7 +292,7 @@ end function PyBeliefPropDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw("The `PyBeliefPropDecoder` depends on the package `PyQDecoders` but you have not installed or imported `PyQDecoders` yet. Immediately after you import `PyQDecoders`, the `PyBeliefPropDecoder` will be available.") + throw(THROW_MISSING_PyQDecoders) end return ext.PyBeliefPropDecoder(args...; kwargs...) end @@ -301,7 +301,7 @@ end function PyBeliefPropOSDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw("The `PyBeliefPropOSDecoder` depends on the package `PyQDecoders` but you have not installed or imported `PyQDecoders` yet. Immediately after you import `PyQDecoders`, the `PyBeliefPropOSDecoder` will be available.") + throw(THROW_MISSING_PyQDecoders) end return ext.PyBeliefPropOSDecoder(args...; kwargs...) end @@ -310,7 +310,7 @@ end function PyMatchingDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw("The `PyMatchingDecoder` depends on the package `PyQDecoders` but you have not installed or imported `PyMatchingDecoder` yet. Immediately after you import `PyQDecoders`, the `PyMatchingDecoder` will be available.") + throw(THROW_MISSING_PyQDecoders) end return ext.PyMatchingDecoder(args...; kwargs...) end diff --git a/src/entanglement.jl b/src/entanglement.jl index 2e1e7ed97..b66dc2fdf 100644 --- a/src/entanglement.jl +++ b/src/entanglement.jl @@ -152,7 +152,7 @@ function bigram(state::AbstractStabilizer; clip::Bool=true)::Matrix{Int} # JET-X for i in 1:rows l = findfirst(j->|(tab[i,j]...), 1:columns) r = findlast(j->|(tab[i,j]...), 1:columns) - (isnothing(l) || isnothing(r)) && throw(DomainError("the tableau is inconsistent (check if it is clip-canonicalized and Hermitian)")) + (isnothing(l) || isnothing(r)) && throw(DomainError(THROW_INCONSISTENT_TABLEAU)) bg[i, 1] = l bg[i, 2] = r end diff --git a/src/grouptableaux.jl b/src/grouptableaux.jl index 538aef4d9..0d5df5e4c 100644 --- a/src/grouptableaux.jl +++ b/src/grouptableaux.jl @@ -1,3 +1,4 @@ +include("throws.jl") """ A tableau representation of the non-commutative canonical form of a set of Paulis, which is used in [`commutify`](@ref). @@ -123,7 +124,7 @@ function groupify(s::Stabilizer; phases=false) # `Stabilizer` s), then multiply each one by a different subset of the elements in s to # create all 2ⁿ unique elements in the group generated by s, then return the `Tableau`. if phases == true - throw(ArgumentError("in groupify phases=true functionality not yet implemented")) + throw(ArgumentError(THROW_PHASE_FUNCTIONALITY_UNAVAILABLE_GROUPIFY)) end gen_set = minimal_generating_set(s) n = length(gen_set)::Int diff --git a/src/linalg.jl b/src/linalg.jl index ccecdf632..d7af24ac4 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -1,3 +1,4 @@ +include("throws.jl") function permutesystems(c::CliffordOperator,p) # TODO this is a slow stupid implementation CliffordOperator(Tableau([tab(c)[i][p] for i in 1:2*nqubits(c)][vcat(p,p.+nqubits(c))])) end @@ -101,10 +102,10 @@ end function logdot(s1::Stabilizer, s2::Stabilizer) if nqubits(s1)!=length(s1) || nqubits(s2)!=length(s2) # TODO implement this - throw(DomainError("Only pure (not mixed) states are supported when calculating inner product.")) + throw(DomainError(THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_DOTPROD)) end if nqubits(s1)!=nqubits(s2) - throw(DimensionMismatch("Inner product can be calculated only between states with the same number of qubits.")) + throw(DimensionMismatch(THROW_NQUBITS)) end c1_inv = inv(CliffordOperator(tab(MixedDestabilizer(copy(s1))))) s2_prime = canonicalize!(c1_inv*s2) @@ -122,9 +123,9 @@ function logdot(s1::Stabilizer, s2::Stabilizer) return k end -LinearAlgebra.rank(s::Stabilizer) = throw(BadDataStructure("Using a `Stabilizer` type does not permit automatic tracking of the rank. Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually.", +LinearAlgebra.rank(s::Stabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE, :rank, :Stabilizer)) -LinearAlgebra.rank(s::Destabilizer) = throw(BadDataStructure("Using a `Destabilizer` type does not permit automatic tracking of the rank. Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually.", +LinearAlgebra.rank(s::Destabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE, :rank, :Destabilizer)) LinearAlgebra.rank(s::MixedStabilizer) = s.rank LinearAlgebra.rank(s::MixedDestabilizer) = s.rank diff --git a/src/misc_ops.jl b/src/misc_ops.jl index c6e6287f8..49444edbd 100644 --- a/src/misc_ops.jl +++ b/src/misc_ops.jl @@ -1,5 +1,5 @@ import QuantumInterface: nsubsystems - +include("throws.jl") """A Stabilizer measurement on the entirety of the quantum register. `projectrand!(state, pauli)` and `apply!(state, PauliMeasurement(pauli))` give the same (possibly non-deterministic) result. @@ -33,7 +33,7 @@ struct SparseGate{T<:Tableau} <: AbstractCliffordOperator # TODO simplify type p indices::Vector{Int} function SparseGate(cliff::CliffordOperator{T}, indices::Vector{Int}) where T<:Tableau if length(indices) != nqubits(cliff) - throw(ArgumentError("The number of target qubits (indices) must match the qubit count in the CliffordOperator.")) + throw(ArgumentError(THROW_BOUNDS)) end new{T}(cliff, indices) end @@ -44,7 +44,7 @@ SparseGate(c,t::Tuple) = SparseGate(c,collect(t)) function apply!(state::AbstractStabilizer, g::SparseGate; kwargs...) m = maximum(g.indices) if m > nqubits(state) - throw(ArgumentError(lazy"SparseGate was attempted on invalid qubit index $(m) when the state contains only $(nqubits(state)) qubits.")) + throw(ArgumentError(THROW_BOUNDS)) end apply!(state, g.cliff, g.indices; kwargs...) end @@ -136,7 +136,7 @@ function applywstatus!(s::AbstractQCState, v::VerifyOp) # XXX It assumes the oth # TODO QuantumClifford should implement some submatrix comparison r,n = size(v.good_state) if(r!=n) - throw(ArgumentError("""The argument you have provided for good_state is not a logical state within the codespace. Expected a pure $n - qubit stabilizer state (i.e. $n independent stabilizer generators on $n qubits), but good_state has only $r independent stabilizer generators.""")) + throw(ArgumentError(THROW_NOT_STABILIZER_STATE)) end canonicalize_rref!(quantumstate(s),v.indices) # Document why rref is used sv = tab(s) diff --git a/src/nonclifford.jl b/src/nonclifford.jl index eac7604f1..a72869adc 100644 --- a/src/nonclifford.jl +++ b/src/nonclifford.jl @@ -1,3 +1,4 @@ +include("throws.jl") """ $(TYPEDEF) @@ -42,7 +43,7 @@ end function GeneralizedStabilizer(state) n = nqubits(state) md = MixedDestabilizer(state) - rank(md)==n || throw(ArgumentError(lazy"""Attempting to convert a `Stabilizer`-like object to `GeneralizedStabilizer` object failed, because the initial state does not represent a pure state. Currently only pure states can be used to initialize a `GeneralizedStabilizer` mixture of stabilizer states.""")) + rank(md)==n || throw(ArgumentError(THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_STABILIZER)) GeneralizedStabilizer(md, DefaultDict(0.0im, (falses(n),falses(n))=>1.0+0.0im)) # TODO maybe it should default to Destabilizer, not MixedDestabilizer end @@ -361,18 +362,10 @@ struct PauliChannel{T,S} <: AbstractPauliChannel paulis::T weights::S function PauliChannel(paulis, weights) - length(paulis) == length(weights) || throw(ArgumentError(lazy""" - Attempting to construct a `PauliChannel` failed. - The length of the vectors of weights and of Pauli operator pairs differs - ($(length(weights)) and $(length(paulis)) respectively). - """)) + length(paulis) == length(weights) || throw(ArgumentError(THROW_BOUNDS)) n = nqubits(paulis[1][1]) for p in paulis - n == nqubits(p[1]) == nqubits(p[2]) || throw(ArgumentError(lazy""" - You are attempting to construct a `PauliChannel` but have provided Pauli operators - that are not all of the same size (same number of qubits). - Please ensure that all of the Pauli operators being provided of of the same size. - """)) + n == nqubits(p[1]) == nqubits(p[2]) || throw(ArgumentError(THROW_PAULI_BOUNDS)) end new{typeof(paulis),typeof(weights)}(paulis,weights) end @@ -401,7 +394,7 @@ nqubits(pc::PauliChannel) = nqubits(pc.paulis[1][1]) See also: [`GeneralizedStabilizer`](@ref), [`PauliChannel`](@ref), [`UnitaryPauliChannel`](@ref) """ function apply!(state::GeneralizedStabilizer, gate::AbstractPauliChannel; prune_threshold=1e-10) - nqubits(state) == nqubits(gate) || throw(DimensionMismatch(lazy"GeneralizedStabilizer has $(nqubits(state)) qubits, but PauliChannel has $(nqubits(gate)). Use `embed` to create an appropriately padded PauliChannel.")) + nqubits(state) == nqubits(gate) || throw(DimensionMismatch(THROW_EMBEDDING_REQUIRED)) dict = state.destabweights stab = state.stab dtype = valtype(dict) diff --git a/src/project_trace_reset.jl b/src/project_trace_reset.jl index 2d27142ce..9808da88e 100644 --- a/src/project_trace_reset.jl +++ b/src/project_trace_reset.jl @@ -1,3 +1,4 @@ +include("throws.jl") """ Generate a Pauli operator by using operators from a given the Stabilizer. @@ -349,7 +350,7 @@ function _project!(d::Destabilizer,pauli::PauliOperator;keep_result::Val{Bkr}=Va end if anticommutes == 0 if n != nqubits(stabilizer) - throw(BadDataStructure("`Destabilizer` can not efficiently (faster than n^3) detect whether you are projecting on a stabilized or a logical operator. Switch to one of the `Mixed*` data structures.", + throw(BadDataStructure(THROW_INEFFICIENT_DESTABILIZER, :project!, :Destabilizer)) end @@ -673,8 +674,8 @@ These qubits are traced out first, which could lead to "nonlocal" changes in the tableau. """ function reset_qubits!(s::Stabilizer, newstate, qubits; phases=true) - nqubits(newstate)==length(qubits) || throw(DimensionMismatch("`qubits` and `newstate` have to be of consistent size")) - length(qubits) <= nqubits(s) || throw(DimensionMismatch("the stabilizer is not big enough to contain the new state")) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_NQUBITS)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_SIZE)) n = nqubits(s) s, x, z = canonicalize!(s,ranks=true) # TODO this is unnecessary, but it provides for nicely formatted tableaux; consider removing it for speed reasons _, rref_i = canonicalize_rref!((@view s[1:z]),qubits,phases=phases) @@ -691,8 +692,8 @@ end $TYPEDSIGNATURES """ function reset_qubits!(s::MixedStabilizer, newstate, qubits; phases=true) # TODO create the necessary interfaces so that Stabilizer and MixedStabilizer share this code - nqubits(newstate)==length(qubits) || throw(DimensionMismatch("`qubits` and `newstate` have to be of consistent size")) - length(qubits) <= nqubits(s) || throw(DimensionMismatch("the stabilizer is not big enough to contain the new state")) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_NQUBITS)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_BOUNDS)) n = nqubits(s) sv = stabilizerview(s) sv, rref_i = canonicalize_rref!(sv,qubits,phases=phases) @@ -708,8 +709,8 @@ $TYPEDSIGNATURES """ function reset_qubits!(s::MixedDestabilizer, newstate::AbstractStabilizer, qubits; phases=true) # TODO this is really inefficient _phases = Val(phases) - nqubits(newstate)==length(qubits) || throw(DimensionMismatch("`qubits` and `newstate` have to be of consistent size")) - length(qubits) <= nqubits(s) || throw(DimensionMismatch("the stabilizer is not big enough to contain the new state")) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_SIZE)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_BOUNDS)) newstatestab = stabilizerview(newstate) traceout!(s,qubits) for pauli in newstatestab diff --git a/src/symbolic_cliffords.jl b/src/symbolic_cliffords.jl index 97681e7a6..07f269f8e 100644 --- a/src/symbolic_cliffords.jl +++ b/src/symbolic_cliffords.jl @@ -1,5 +1,5 @@ using Random: AbstractRNG, GLOBAL_RNG - +include("throws.jl") """Supertype of all symbolic operators. Subtype of `AbstractCliffordOperator`""" abstract type AbstractSymbolicOperator <: AbstractCliffordOperator end """Supertype of all single-qubit symbolic operators.""" @@ -92,7 +92,7 @@ macro qubitop1(name, kernel, inv_kernel) quote struct $(esc(prefixname)) <: AbstractSingleQubitOperator q::Int - $(esc(prefixname))(q) = if q<=0 throw(NoZeroQubit) else new(q) end + $(esc(prefixname))(q) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q) end end @doc $docstring $prefixname @inline $(esc(:qubit_kernel))(::$prefixname, x, z) = $kernel @@ -121,7 +121,7 @@ See also: [`SingleQubitOperator`](@ref) """ struct sId1 <: AbstractSingleQubitOperator q::Int - sId1(q) = if q<=0 throw(NoZeroQubit) else new(q) end + sId1(q) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q) end end function _apply!(stab::AbstractStabilizer, ::sId1; phases::Val{B}=Val(true)) where B stab @@ -171,7 +171,7 @@ struct SingleQubitOperator <: AbstractSingleQubitOperator zz::Bool px::Bool pz::Bool - SingleQubitOperator(q,args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + SingleQubitOperator(q,args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end function _apply!(stab::AbstractStabilizer, op::SingleQubitOperator; phases::Val{B}=Val(true)) where B # TODO Generated functions that simplify the whole `if phases` branch might be a good optimization, but a quick benchmakr comparing sHadamard to SingleQubitOperator(sHadamard) did not show a worthwhile difference. s = tab(stab) @@ -223,7 +223,7 @@ function SingleQubitOperator(o::SingleQubitOperator, qubit::Int) return SingleQubitOperator(qubit, o.xx, o.xz, o.zx, o.zz, o.px, o.pz) end function SingleQubitOperator(op::CliffordOperator, qubit) - nqubits(op)==1 || throw(DimensionMismatch("You are trying to convert a multiqubit `CliffordOperator` into a symbolic `SingleQubitOperator`.")) + nqubits(op)==1 || throw(DimensionMismatch(THROW_INVALID_CONVERSION_TO_SINGLEQUBIT)) SingleQubitOperator(qubit,tab(op)[1,1]...,tab(op)[2,1]...,(~).(iszero.(tab(op).phases))...) end SingleQubitOperator(op::CliffordOperator) = SingleQubitOperator(op, 1) @@ -231,10 +231,10 @@ SingleQubitOperator(op::CliffordOperator) = SingleQubitOperator(op, 1) CliffordOperator(op::AbstractSingleQubitOperator, n; kw...) = CliffordOperator(SingleQubitOperator(op), n; kw...) function CliffordOperator(op::SingleQubitOperator, n; compact=false) if compact - n==1 || throw(ArgumentError("Set `n=1` as a `SingleQubitOperator` being compacted (`compact=true`) has to result in a 1×1 `CliffordOperator`.")) + n==1 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR)) return CliffordOperator(Tableau([op.px ? 0x2 : 0x0, op.pz ? 0x2 : 0x0],[op.xx op.xz; op.zx op.zz])) else - n >= op.q || throw(DimensionMismatch("Set a larger `n`, otherwise the `SingleQubitOperator` can not fit in the allocated `CliffordOperator`. Use `compact=true` if you want to discard the target index.")) + n >= op.q || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION)) c = one(CliffordOperator, n) c[op.q,op.q] = op.xx, op.xz # TODO define an `embed` helper function c[n+op.q,op.q] = op.zx, op.zz @@ -346,7 +346,7 @@ macro qubitop2(name, kernel, inv_kernel) struct $(esc(prefixname)) <: AbstractTwoQubitOperator q1::Int q2::Int - $(esc(prefixname))(q1,q2) = if q1<=0 || q2<=0 throw(NoZeroQubit) elseif q1==q2 throw(ArgumentError("Failed to create a two qubit gate because the two qubits it acts on have the same index. The qubit indices have to be different.")) else new(q1,q2) end + $(esc(prefixname))(q1,q2) = if q1<=0 || q2<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) elseif q1==q2 throw(ArgumentError(THROW_INVALID_TWO_QUBIT_GATE)) else new(q1,q2) end end @doc $docstring $prefixname @inline $(esc(:qubit_kernel))(::$prefixname, x1, z1, x2, z2) = $kernel @@ -407,10 +407,10 @@ Then we can use a truth-table to boolean formula converter, e.g. https://www.dco function CliffordOperator(op::AbstractTwoQubitOperator, n; compact=false) if compact - n==2 || throw(ArgumentError("Set `n=2` as a `TwoQubitOperator` being compacted (`compact=true`) has to result in a 2×2 `CliffordOperator`.")) + n==2 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR)) return CliffordOperator(typeof(op)) else - n >= max(op.q1,op.q2) || throw(DimensionMismatch("Set a larger `n`, otherwise the `TwoQubitOperator` can not fit in the allocated `CliffordOperator`. Use `compact=true` if you want to discard the target index.")) + n >= max(op.q1,op.q2) || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION)) c = one(CliffordOperator, n) _c = CliffordOperator(typeof(op)) for (i,q) in ((1,op.q1),(2,op.q2)) @@ -513,21 +513,21 @@ end struct sMX <: AbstractMeasurement qubit::Int bit::Int - sMX(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMX(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end """Symbolic single qubit Y measurement. See also [`Register`](@ref), [`projectYrand!`](@ref), [`sMX`](@ref), [`sMZ`](@ref)""" struct sMY <: AbstractMeasurement qubit::Int bit::Int - sMY(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMY(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end """Symbolic single qubit Z measurement. See also [`Register`](@ref), [`projectZrand!`](@ref), [`sMX`](@ref), [`sMY`](@ref)""" struct sMZ <: AbstractMeasurement qubit::Int bit::Int - sMZ(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMZ(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end sMX(i) = sMX(i,0) @@ -624,7 +624,7 @@ See also: [`Reset`](@ref), [`sMZ`](@ref)""" struct sMRZ <: AbstractOperation qubit::Int bit::Int - sMRZ(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMRZ(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end """Measure a qubit in the X basis and reset to the |+⟩ state. @@ -633,7 +633,7 @@ See also: [`sMRZ`](@ref), [`Reset`](@ref), [`sMZ`](@ref)""" struct sMRX <: AbstractOperation qubit::Int bit::Int - sMRX(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMRX(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end """Measure a qubit in the Y basis and reset to the |i₊⟩ state. @@ -642,7 +642,7 @@ See also: [`sMRZ`](@ref), [`Reset`](@ref), [`sMZ`](@ref)""" struct sMRY <: AbstractOperation qubit::Int bit::Int - sMRY(q, args...) = if q<=0 throw(NoZeroQubit) else new(q,args...) end + sMRY(q, args...) = if q<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) else new(q,args...) end end sMRX(i) = sMRX(i,0) diff --git a/src/throws.jl b/src/throws.jl index b0be154c7..2a7768c9b 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -78,4 +78,111 @@ const THROW_INVALID_QUANTUM_REED_MULLER = "Invalid parameters: m must be bigger than 2 in order to have a valid code." const THROW_INVALID_PARAMETERS_TILLICH_ZEMOR = -"Conditions for the existence of `M` in `H = [C | M]` are not satisfied." \ No newline at end of file +"Conditions for the existence of `M` in `H = [C | M]` are not satisfied." + +const THROW_INVALID_PARAMETERS_CLIFFORD = +"Input tableau should be of size 2n×n (top half is the X mappings and the bottom half are the Z mappings)." + +const THROW_INVALID_ACTION_QUBITS = +"The tableau and the provided operator need to act on the same number of qubits. +Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error." + +const THROW_INVALID_PARAMETERS_BCH_ARG = +"""Conditions for valid BCH(m, t) arguments: +- m ≥ 3 +- t < 2ᵐ⁻¹ +- m*t ≤ 2ᵐ - 1 +""" + +const THROW_MISSING_HECKE = +"You've invoked a function which depends on the package `Hecke` but you have not installed or imported it yet. +Immediately after you import `Hecke`, the function will be available." + +const THROW_MISSING_OSCAR = +"You've invoked a function which depends on the package `Oscar` but you have not installed or imported it yet. +Immediately after you import `Oscar`, the function will be available." + +const THROW_MISSING_LDPCDecoders = +"You've invoked a function which depends on the package `LDPCDecoders` but you have not installed or imported it yet. +Immediately after you import `LDPCDecoders`, the function will be available." + +const THROW_MISSING_PyQDecoders = +"You've invoked a function which depends on the package `PyQDecoders` but you have not installed or imported it yet. +Immediately after you import `PyQDecoders`, the function will be available." + +const THROW_INVALID_PARAMETERS_NOISE = +"The input noise should be between 0 and 1." + +const THROW_INVALID_LOGICAL_OPERATOR = +"`logical_operator_type` must be :X or :Z" + +const THROW_CHECKS_MISSING = +"Codes of the type used do not have separate X and Z parity checks, either because they are not a CSS code +and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library." + +const THROW_INCONSISTENT_TABLEAU = +"the tableau is inconsistent (check if it is clip-canonicalized and Hermitian)" + +const THROW_PHASE_FUNCTIONALITY_UNAVAILABLE_GROUPIFY = +"in groupify phases=true functionality not yet implemented" + +const THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_DOTPROD = +"Only pure (not mixed) states are supported when calculating inner product." + +const THROW_BAD_DATA_STRUCTURE = +"You've used a type(`Stabilizer` or `Destabilizer`) does not permit automatic tracking of the rank. +Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually." + +const THROW_NOT_STABILIZER_STATE = +"""The argument you have provided for good_state is not a logical state within the codespace. +Expected a pure qubit stabilizer state (i.e. independent stabilizer generators on be equal to number of qubits)""" + +const THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_STABILIZER = +"""Attempting to convert a `Stabilizer`-like object to `GeneralizedStabilizer` object failed, +because the initial state does not represent a pure state. +Currently only pure states can be used to initialize a `GeneralizedStabilizer` mixture of stabilizer states.""" + +const THROW_PAULI_BOUNDS = +""" +You are attempting to construct a `PauliChannel` but have provided Pauli operators +that are not all of the same size (same number of qubits). +Please ensure that all of the Pauli operators being provided of of the same size. +""" + +const THROW_EMBEDDING_REQUIRED = +"The number of qubits in the GeneralizedStabilizer state does not match the number of qubits in the Pauli channel. + Use `embed` to pad the PauliChannel so it acts on the correct number of qubits." + +const THROW_INEFFICIENT_DESTABILIZER = +"`Destabilizer` can not efficiently (faster than n^3) detect whether you are projecting on a stabilized or a logical operator. +Switch to one of the `Mixed*` data structures." + +const THROW_ONLY_FULL_RANK_DESTABILIZER_SUPPORTED = +"Only full-rank `Destabilizer` can be converted to `MixedDestabilizer` with specific rank. Try not specifying `r`." + +const THROW_PHASES = +"Only {±1,±i} are permitted as phases." + +const THROW_ROW_MISMATCH_TABLEAUX = +"All input Tableaux/Stabilizers musT have the same number of rows." + +const THROW_NO_ZERO_QUBIT = +"Qubit indices have to be larger than zero, +but you are attempting to create a gate acting on a qubit with a non-positive index. Ensure indexing always starts from 1." + +const THROW_INVALID_CONVERSION_TO_SINGLEQUBIT = +"You are trying to convert a multiqubit `CliffordOperator` into a symbolic `SingleQubitOperator`." + +const THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION = +"Set a larger `n`, otherwise the `SingleQubitOperator` or `TwoQubitOperator`(whichever is being used) can not fit in the allocated `CliffordOperator`. + Use `compact=true` if you want to discard the target index." + +const THROW_INVALID_TWO_QUBIT_GATE = +"Failed to create a two qubit gate because the two qubits it acts on have the same index. The qubit indices have to be different." + +const THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR = +"Set `n=k` when compacting (`compact=true`) a `k`-qubit operator, so that it results in a `k×k` `CliffordOperator`." + +const THROW_INVALID_BASIS_REP = +"`basis` should be one of :X, :Y, or :Z" + diff --git a/src/useful_states.jl b/src/useful_states.jl index fd89d08db..5d37fe225 100644 --- a/src/useful_states.jl +++ b/src/useful_states.jl @@ -1,3 +1,4 @@ +include("throws.jl") """A multiqubit operator corresponding to all identities except for Pauli Z at `i`. See also: [`sY`](@ref), [`sMY`](@ref)""" function single_z(n,i) p = zero(PauliOperator, n) @@ -28,7 +29,7 @@ function Base.one(::Type{T}, n; basis=:Z) where {T<:Tableau}# TODO support `basi elseif basis==:Z T(falses(n,n),LinearAlgebra.I(n)) else - throw(ArgumentError("`basis` should be one of :X, :Y, or :Z")) + throw(ArgumentError(THROW_INVALID_BASIS_REP)) end end Base.one(::Type{<:Stabilizer}, n; basis=:Z) = Stabilizer(one(Tableau,n; basis)) # TODO make it type preserving From 16176c69da8534f4a52a16f92f306c918a7be95c Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Mon, 18 Aug 2025 00:04:22 +0530 Subject: [PATCH 10/11] refactor: remove single use error messages and error messages used in just one file from throws.jl --- Project.toml | 6 +- .../QuantumCliffordGPUExt.jl | 1 - ext/QuantumCliffordGPUExt/utils.jl | 2 + ext/QuantumCliffordHeckeExt/lacross.jl | 2 +- ext/QuantumCliffordHeckeExt/lifted_product.jl | 7 +- .../min_distance_mixed_integer_programming.jl | 4 +- .../QuantumCliffordOscarExt.jl | 1 - .../d_dimensional_codes.jl | 12 +- lib/QECCore/src/codes/classical/golay.jl | 2 +- lib/QECCore/src/codes/classical/hamming.jl | 2 +- lib/QECCore/src/codes/quantum/color_codes.jl | 6 + .../quantum/delfosse_reichardt_823_code.jl | 2 +- .../codes/quantum/delfosse_reichardt_code.jl | 4 +- .../quantum/delfosse_reichardt_repcode.jl | 2 +- .../src/codes/quantum/quantumreedmuller.jl | 2 +- .../quantum/quantumtannergraphproduct.jl | 2 +- lib/QECCore/src/codes/quantum/tillichzemor.jl | 3 + src/QuantumClifford.jl | 11 +- src/dense_cliffords.jl | 2 +- src/ecc/ECC.jl | 11 +- src/ecc/codes/classical/bch.jl | 6 +- src/ecc/codes/classical/lifted.jl | 2 +- src/ecc/codes/d_dimensional_codes.jl | 4 +- src/ecc/codes/lifted_product.jl | 4 +- src/ecc/decoder_pipeline.jl | 23 +-- src/entanglement.jl | 2 +- src/grouptableaux.jl | 2 +- src/linalg.jl | 10 +- src/misc_ops.jl | 3 +- src/nonclifford.jl | 13 +- src/project_trace_reset.jl | 17 +- src/symbolic_cliffords.jl | 20 ++- src/throws.jl | 156 ------------------ src/useful_states.jl | 2 +- 34 files changed, 124 insertions(+), 224 deletions(-) diff --git a/Project.toml b/Project.toml index 27e729e5c..d115b7a22 100644 --- a/Project.toml +++ b/Project.toml @@ -38,9 +38,6 @@ PyQDecoders = "17f5de1a-9b79-4409-a58d-4d45812840f7" Quantikz = "b0d11df0-eea3-4d79-b4a5-421488cbf74b" QuantumOpticsBase = "4f57444f-1401-5e15-980d-4471b28d5678" -[sources.QECCore] -path = "lib/QECCore" - [extensions] QuantumCliffordGPUExt = "CUDA" QuantumCliffordHeckeExt = "Hecke" @@ -87,3 +84,6 @@ SparseArrays = "1.10" Statistics = "1.10" SumTypes = "0.5" julia = "1.10" + +[sources.QECCore] +path = "lib/QECCore" diff --git a/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl b/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl index b1faca4bc..484b2f452 100644 --- a/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl +++ b/ext/QuantumCliffordGPUExt/QuantumCliffordGPUExt.jl @@ -11,6 +11,5 @@ include("apply.jl") include("pauli_frames.jl") include("fastmemlayout.jl") include("apply_noise.jl") -include("../../src/throws.jl") end diff --git a/ext/QuantumCliffordGPUExt/utils.jl b/ext/QuantumCliffordGPUExt/utils.jl index c26c637f6..4c68740f6 100644 --- a/ext/QuantumCliffordGPUExt/utils.jl +++ b/ext/QuantumCliffordGPUExt/utils.jl @@ -1,3 +1,5 @@ +const THROW_INVALID_CUDA_ARG = +"First argument to @run_cuda should be a function call" macro run_cuda(call, ndrange) # destructure the kernel call Meta.isexpr(call, :call) || throw(ArgumentError(THROW_INVALID_CUDA_ARG)) diff --git a/ext/QuantumCliffordHeckeExt/lacross.jl b/ext/QuantumCliffordHeckeExt/lacross.jl index a9003a906..378572457 100644 --- a/ext/QuantumCliffordHeckeExt/lacross.jl +++ b/ext/QuantumCliffordHeckeExt/lacross.jl @@ -142,7 +142,7 @@ struct LaCross <: AbstractCSSCode """A flag indicating whether to use the full-rank rectangular matrix (`true`) or the original circulant matrix (`false`).""" full_rank::Bool function LaCross(n, h, full_rank) - n <= 0 && throw(ArgumentError(THROW_REQUIRED_POSITIVE_ARG)) + n <= 0 && throw(ArgumentError("Block length must be positive.")) new(n, h, full_rank) end end diff --git a/ext/QuantumCliffordHeckeExt/lifted_product.jl b/ext/QuantumCliffordHeckeExt/lifted_product.jl index 440b7ad3e..7ed73456d 100644 --- a/ext/QuantumCliffordHeckeExt/lifted_product.jl +++ b/ext/QuantumCliffordHeckeExt/lifted_product.jl @@ -1,3 +1,8 @@ +const THROW_REPR_NEEDS_COMMUTATIVE_ALGEBRA = +"The group algebra must be commutative when using a single `repr` function,\ +which is not the case here. Please specify separate `A_repr` and `B_repr` \ +instead of a single `repr`. The default choice of\ +`A_repr=right_repr_matrix, B_repr=left_repr_matrix` is frequently sufficient." right_repr_matrix(x) = representation_matrix(x, :right) left_repr_matrix(x) = representation_matrix(x, :left) @@ -548,7 +553,7 @@ See also: [`bicycle_codes`](@ref), [`generalized_bicycle_codes`](@ref), [`two_bl [`honeycomb_color_codes`](@ref). """ function honeycomb_color_codes(ℓ::Int, m::Int) - (ℓ % 3 == 0 && m % 3 == 0) || throw(ArgumentError(THROW_MUST_BE_DIVISIBLE_BY_3)) + (ℓ % 3 == 0 && m % 3 == 0) || throw(ArgumentError("Both ℓ and m must be divisible by 3")) GA = group_algebra(GF(2), abelian_group([ℓ, m])) x, y = gens(GA) c = 1 + x + x*y diff --git a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl index 430e58ecb..f900f82c6 100644 --- a/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl +++ b/ext/QuantumCliffordJuMPExt/min_distance_mixed_integer_programming.jl @@ -254,9 +254,9 @@ function _minimum_distance(hx, lx, opt, opt_summary, time_limit) # Ensure the model is solved and feasible if !is_solved_and_feasible(model) if termination_status(model) == MOI.MEMORY_LIMIT - throw(ErrorException(THROW_MODEL_MEMORY_LIMIT)) + throw(ErrorException("Model exceeded memory limits")) elseif termination_status(model) == MOI.TIME_LIMIT - throw(ErrorException(THROW_MODEL_TIME_LIMIT)) + throw(ErrorException("Model exceeded time limit")) else throw(ErrorException("Model failed to solve :$(termination_status(model))")) end diff --git a/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl b/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl index 4f68c80bb..7cedbcf7d 100644 --- a/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl +++ b/ext/QuantumCliffordOscarExt/QuantumCliffordOscarExt.jl @@ -31,6 +31,5 @@ include("types.jl") include("direct_product.jl") include("group_presentation.jl") include("d_dimensional_codes.jl") -include("../../src/throws.jl") end # module diff --git a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl index cb50212bc..8f08c809a 100644 --- a/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl +++ b/ext/QuantumCliffordOscarExt/d_dimensional_codes.jl @@ -1,5 +1,9 @@ abstract type DDimensionalCode <: AbstractCSSCode end +THROW_INVALID_CODE_DIMENSION(code, D) = +"Dimension of the $code code must be at least 2 (got D=$D)." +"" + """Construct the chain complex for the repetition code of length `L`.""" function _repcode_chain_complex(L::Int) F = GF(2) @@ -376,7 +380,7 @@ struct DDimensionalSurfaceCode <: DDimensionalCode L::Int function DDimensionalSurfaceCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION)) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION("Surface", D))) new(D, L) end end @@ -512,7 +516,7 @@ struct DDimensionalToricCode <: DDimensionalCode L::Int function DDimensionalToricCode(D::Int, L::Int) - D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION)) + D ≥ 2 || throw(ArgumentError(THROW_INVALID_CODE_DIMENSION("Toric", D))) new(D, L) end end @@ -609,12 +613,12 @@ function code_k(c::DDimensionalCode) end function metacheck_matrix_x(c::DDimensionalCode) - c.D ≥ 4 || throw(ArgumentError(THROW_INVALID_X_METACHECKS)) + c.D ≥ 4 || throw(ArgumentError("`X`-metachecks (`Mx`) require `D ≥ 4`")) return Matrix(boundary_maps(c)[4]) # Mx end function metacheck_matrix_z(c::DDimensionalCode) - c.D ≥ 3 || throw(ArgumentError(THROW_INVALID_Z_METACHECKS)) + c.D ≥ 3 || throw(ArgumentError("`Z`-metachecks (`Mz`) require `D ≥ 3`")) return Matrix(boundary_maps(c)[1]') # Mz end diff --git a/lib/QECCore/src/codes/classical/golay.jl b/lib/QECCore/src/codes/classical/golay.jl index 8b7952fa9..ffed3d8f6 100644 --- a/lib/QECCore/src/codes/classical/golay.jl +++ b/lib/QECCore/src/codes/classical/golay.jl @@ -31,7 +31,7 @@ struct Golay <: AbstractCECC function Golay(n) if !(n in (23, 24)) - throw(ArgumentError(THROW_INVALID_PARAMETERS_GOLAY)) + throw(ArgumentError("Invalid parameters: `n` must be either 24 or 23 to obtain a valid code.")) end new(n) end diff --git a/lib/QECCore/src/codes/classical/hamming.jl b/lib/QECCore/src/codes/classical/hamming.jl index 99abb3860..4947577fe 100644 --- a/lib/QECCore/src/codes/classical/hamming.jl +++ b/lib/QECCore/src/codes/classical/hamming.jl @@ -22,7 +22,7 @@ struct Hamming <: AbstractCECC r::Int function Hamming(r) if r < 2 - throw(ArgumentError(THROW_INVALID_PARAMETERS_HAMMING)) + throw(ArgumentError("Invalid parameters: `r` must be ≥ 2 to obtain a valid code.")) end new(r) end diff --git a/lib/QECCore/src/codes/quantum/color_codes.jl b/lib/QECCore/src/codes/quantum/color_codes.jl index f74e12444..5c587aa7e 100644 --- a/lib/QECCore/src/codes/quantum/color_codes.jl +++ b/lib/QECCore/src/codes/quantum/color_codes.jl @@ -1,5 +1,11 @@ abstract type ColorCode <: AbstractCSSCode end +const THROW_COLOR_CODES_ODD = +"Only odd distance triangular color codes are allowed.\nRefer to https://arxiv.org/abs/1108.5738" + +const THROW_COLOR_CODES_MIN_DIST = +"Smallest allowed distance is 3.\nRefer to https://arxiv.org/abs/1108.5738" + """Planar color codes that encode a single logical qubit.""" abstract type TriangularCode <: ColorCode end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl index 0b49a9103..cd840a889 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_823_code.jl @@ -56,7 +56,7 @@ struct DelfosseReichardt823 <: AbstractQECC """The number of blocks in the Delfosse-Reichardt generalized [[8, 2, 3]] code.""" p::Int function DelfosseReichardt823(p) - p < 1 && throw(ArgumentError(THROW_DELFOSSE_823_MIN_BLOCKS)) + p < 1 && throw(ArgumentError("The number of blocks must be at least 1 to construct a valid code.")) new(p) end end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl index a647d6962..0d503439c 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl @@ -91,7 +91,9 @@ struct DelfosseReichardt <: AbstractCSSCode throw(ArgumentError(THROW_INVALID_PARAMETERS_REEDMULLER)) end if !iszero(mod.(parity_matrix(ReedMuller(r,m))*parity_matrix(ReedMuller(r,m))',2)) - throw(ArgumentError(THROW_DELFOSSE_SELF_ORTHOGONAL)) + throw(ArgumentError("The `Reed-Muller` parity check matrix must be 'self-orthogonal' to construct a self-dual +CSS `DelfosseReichardt` code. Use `search_self_orthogonal_rm_codes` to search for good parameters for `Reed-Muller` codes +that provide `self-orthogonal` seeds.")) end new(p,r,m) end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl index e1d60fc9b..c072acd99 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl @@ -58,7 +58,7 @@ struct DelfosseReichardtRepCode <: AbstractCSSCode p::Int function DelfosseReichardtRepCode(p) p < 2 && throw(ArgumentError(THROW_DELFOSSE_MIN_BLOCKS)) - p % 2 != 0 && throw(ArgumentError(THROW_DELFOSSE_REP_MULTIPLE)) + p % 2 != 0 && throw(ArgumentError("The number of blocks must be a multiple of 2.")) new(p) end end diff --git a/lib/QECCore/src/codes/quantum/quantumreedmuller.jl b/lib/QECCore/src/codes/quantum/quantumreedmuller.jl index b7d6b24cb..2039bd72d 100644 --- a/lib/QECCore/src/codes/quantum/quantumreedmuller.jl +++ b/lib/QECCore/src/codes/quantum/quantumreedmuller.jl @@ -21,7 +21,7 @@ struct QuantumReedMuller <: AbstractCSSCode m::Int function QuantumReedMuller(m) if m < 3 - throw(DomainError(THROW_INVALID_QUANTUM_REED_MULLER)) + throw(DomainError("Invalid parameters: m must be bigger than 2 in order to have a valid code.")) end new(m) end diff --git a/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl b/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl index 9714e329c..9bb9bc6de 100644 --- a/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl +++ b/lib/QECCore/src/codes/quantum/quantumtannergraphproduct.jl @@ -203,7 +203,7 @@ julia> code_n(c), code_k(c) struct CyclicQuantumTannerGraphProduct <: AbstractCSSCode m::Int function CyclicQuantumTannerGraphProduct(m::Int) - m > 0 || throw(ArgumentError(THROW_REQUIRED_POSITIVE_ARG)) + m > 0 || throw(ArgumentError("m must be positive.")) new(m) end end diff --git a/lib/QECCore/src/codes/quantum/tillichzemor.jl b/lib/QECCore/src/codes/quantum/tillichzemor.jl index de12d7bec..d43ad8c58 100644 --- a/lib/QECCore/src/codes/quantum/tillichzemor.jl +++ b/lib/QECCore/src/codes/quantum/tillichzemor.jl @@ -1,3 +1,6 @@ +const THROW_INVALID_PARAMETERS_TILLICH_ZEMOR = +"Conditions for the existence of `M` in `H = [C | M]` are not satisfied." + """ $TYPEDEF diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index d112f82d0..30a60dac6 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -105,6 +105,10 @@ const BIG_INT_MINUS_ONE = Ref{BigInt}() const BIG_INT_TWO = Ref{BigInt}() const BIG_INT_FOUR = Ref{BigInt}() +THROW_MISSING_PACKAGE(func, pack) = +"You've invoked `$func` which depends on the package `$pack` but you have not installed or imported it yet. +Immediately after you import `$pack`, the $func will be available." + function __init__() BIG_INT_MINUS_ONE[] = BigInt(-1) BIG_INT_TWO[] = BigInt(2) @@ -654,7 +658,8 @@ function MixedDestabilizer(d::Destabilizer, r::Int) if l==2n MixedDestabilizer(tab(d), r) else - throw(DomainError(THROW_ONLY_FULL_RANK_DESTABILIZER_SUPPORTED)) + throw(DomainError("Only full-rank `Destabilizer` can be converted to `MixedDestabilizer` with specific rank. Try not specifying `r`." +)) end end function MixedDestabilizer(d::Destabilizer) @@ -870,7 +875,7 @@ function Base.:(*)(l::Number, r::PauliOperator) elseif l==-1im p.phase[] = (p.phase[] + 3)&0x3 else - throw(DomainError(l,THROW_PHASES)) + throw(DomainError(l,"Only {±1,±i} are permitted as phases.")) end p end @@ -1057,7 +1062,7 @@ function Base.hcat(tabs::Tableau...) # TODO this implementation is slow as it un for tab in tabs rows_tab, cols_tab = size(tab) if rows_tab != rows - throw(ArgumentError(THROW_ROW_MISMATCH_TABLEAUX)) + throw(ArgumentError("All input Tableaux/Stabilizers musT have the same number of rows.")) end for i in 1:rows for j in 1:cols_tab diff --git a/src/dense_cliffords.jl b/src/dense_cliffords.jl index 31e11d74b..52d0e72f1 100644 --- a/src/dense_cliffords.jl +++ b/src/dense_cliffords.jl @@ -51,7 +51,7 @@ struct CliffordOperator{T<:Tableau,P<:PauliOperator} <: AbstractCliffordOperator # destab = tab(Destabilizer(stab)) # new{typeof(destab.phases),typeof(destab.xzs)}(destab) # TODO be smarter about type signatures here... there should be a better way else - throw(DimensionMismatch(THROW_INVALID_PARAMETERS_CLIFFORD)) + throw(DimensionMismatch("Input tableau should be of size 2n×n (top half is the X mappings and the bottom half are the Z mappings).")) end end end diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index 0a9c2d5f7..aa7973aa7 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -53,8 +53,13 @@ function parity_checks end Only CSS codes have this method. See also: [`parity_checks`](@ref)""" + +const THROW_CHECKS_MISSING(code) = +"Codes of the type $code do not have separate X and Z parity checks, either because they are not a CSS code +and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library." + function parity_matrix_x(code::AbstractECC) - throw(THROW_CHECKS_MISSING) + throw(THROW_CHECKS_MISSING(code)) end """Parity check boolean matrix of a code (only the Z entries in the tableau, i.e. the checks for X errors). @@ -63,7 +68,7 @@ Only CSS codes have this method. See also: [`parity_checks`](@ref)""" function parity_matrix_z(code::AbstractECC) - throw(THROW_CHECKS_MISSING) + throw(THROW_CHECKS_MISSING(code)) end """Check if the code is CSS. @@ -141,7 +146,7 @@ $FIELDS time_limit::Float64=60.0 function DistanceMIPAlgorithm(logical_qubit, logical_operator_type, solver, opt_summary, time_limit) - logical_operator_type ∈ (:X, :Z) || throw(ArgumentError(THROW_INVALID_LOGICAL_OPERATOR)) + logical_operator_type ∈ (:X, :Z) || throw(ArgumentError("`logical_operator_type` must be :X or :Z")) new(logical_qubit, logical_operator_type, solver, opt_summary, time_limit) end end diff --git a/src/ecc/codes/classical/bch.jl b/src/ecc/codes/classical/bch.jl index 7436c060c..315823e24 100644 --- a/src/ecc/codes/classical/bch.jl +++ b/src/ecc/codes/classical/bch.jl @@ -39,9 +39,9 @@ struct BCH <: AbstractPolynomialCode m::Int t::Int function BCH(m, t) - if m < 3 || t >= 2^(m - 1) || m * t > 2^m - 1 - throw(ArgumentError(THROW_INVALID_PARAMETERS_BCH_ARG)) - end + m < 3 && throw(ArgumentError("m must be greater than or equal to 3")) + t >= 2^(m - 1) && throw(ArgumentError("t must be less than 2ᵐ ⁻ ¹")) + m * t > 2^m - 1 && throw(ArgumentError("m*t must be less than or equal to 2ᵐ - 1")) new(m, t) end end diff --git a/src/ecc/codes/classical/lifted.jl b/src/ecc/codes/classical/lifted.jl index 3413de76a..85323b759 100644 --- a/src/ecc/codes/classical/lifted.jl +++ b/src/ecc/codes/classical/lifted.jl @@ -4,7 +4,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LiftedCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw(THROW_MISSING_HECKE) + throw(THROW_MISSING_PACKAGE("LiftedCode", "Hecke")) end return ext.LiftedCode(args...; kwargs...) end diff --git a/src/ecc/codes/d_dimensional_codes.jl b/src/ecc/codes/d_dimensional_codes.jl index 969145133..3dbb8c52e 100644 --- a/src/ecc/codes/d_dimensional_codes.jl +++ b/src/ecc/codes/d_dimensional_codes.jl @@ -7,7 +7,7 @@ Implemented as a package extension with `Oscar`. Check the [QuantumClifford docu function DDimensionalSurfaceCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordOscarExt) if isnothing(ext) - throw(THROW_MISSING_OSCAR) + throw(THROW_MISSING_PACKAGE("DDimensionalSurfaceCode", "Oscar")) end return ext.DDimensionalSurfaceCode(args...; kwargs...) end @@ -18,7 +18,7 @@ Implemented as a package extension with `Oscar`. Check the [QuantumClifford docu function DDimensionalToricCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordOscarExt) if isnothing(ext) - throw(THROW_MISSING_OSCAR) + throw(THROW_MISSING_PACKAGE("DDimensionalToricCode", "Oscar")) end return ext.DDimensionalToricCode(args...; kwargs...) end diff --git a/src/ecc/codes/lifted_product.jl b/src/ecc/codes/lifted_product.jl index 76d607e9f..75683b135 100644 --- a/src/ecc/codes/lifted_product.jl +++ b/src/ecc/codes/lifted_product.jl @@ -4,7 +4,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LPCode(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw(THROW_MISSING_HECKE) + throw(THROW_MISSING_PACKAGE("LPCode", "Hecke")) end return ext.LPCode(args...; kwargs...) end @@ -35,7 +35,7 @@ Implemented as a package extension with Hecke. Check the [QuantumClifford docume function LaCross(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordHeckeExt) if isnothing(ext) - throw(THROW_MISSING_HECKE) + throw(THROW_MISSING_PACKAGE("LaCross", "Hecke")) end return ext.LaCross(args...; kwargs...) end diff --git a/src/ecc/decoder_pipeline.jl b/src/ecc/decoder_pipeline.jl index 3d3d852ae..083fb012a 100644 --- a/src/ecc/decoder_pipeline.jl +++ b/src/ecc/decoder_pipeline.jl @@ -6,6 +6,9 @@ All `AbstractSyndromeDecoder` types are expected to: - have an `evaluate_decoder` method which runs a full simulation but it supports only a small number of ECC protocols""" abstract type AbstractSyndromeDecoder end +THROW_INVALID_NOISE(noisetype, setup) = +"The independent X/Z memory noise in `$setup` should be between 0 and 1." + """Decode a syndrome using a given decoding algorithm.""" function decode end @@ -38,7 +41,7 @@ See also: [`NaiveSyndromeECCSetup`](@ref), [`ShorSyndromeECCSetup`](@ref)""" struct CommutationCheckECCSetup <: AbstractECCSetup xz_noise::Float64 function CommutationCheckECCSetup(xz_noise) - 0<=xz_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) + 0<=xz_noise<=1 || throw(DomainError(xz_noise, "The independent X/Z memory noise in `CommutationCheckECCSetup` should be between 0 and 1.")) new(xz_noise) end end @@ -53,8 +56,8 @@ struct NaiveSyndromeECCSetup <: AbstractECCSetup mem_noise::Float64 two_qubit_gate_noise::Float64 function NaiveSyndromeECCSetup(mem_noise, two_qubit_gate_noise) - 0<=mem_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) - 0<=two_qubit_gate_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) + 0<=mem_noise<=1 || throw(DomainError(mem_noise, "The memory noise in `NaiveSyndromeECCSetup` should be between 0 and 1.")) + 0<=two_qubit_gate_noise<=1 || throw(DomainError(two_qubit_gate_noise, "The two-qubit gate noise in `NaiveSyndromeECCSetup` should be between 0 and 1.")) new(mem_noise, two_qubit_gate_noise) end end @@ -73,8 +76,8 @@ struct ShorSyndromeECCSetup <: AbstractECCSetup mem_noise::Float64 two_qubit_gate_noise::Float64 function ShorSyndromeECCSetup(mem_noise, two_qubit_gate_noise) - 0<=mem_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) - 0<=two_qubit_gate_noise<=1 || throw(DomainError(THROW_INVALID_PARAMETERS_NOISE)) + 0<=mem_noise<=1 || throw(DomainError(mem_noise, "The memory noise in `ShorSyndromeECCSetup` should be between 0 and 1.")) + 0<=two_qubit_gate_noise<=1 || throw(DomainError(two_qubit_gate_noise, "The two-qubit gate noise in `ShorSyndromeECCSetup` should be between 0 and 1.")) new(mem_noise, two_qubit_gate_noise) end end @@ -273,7 +276,7 @@ end function BeliefPropDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt) if isnothing(ext) - throw(THROW_MISSING_LDPCDecoders) + throw(THROW_MISSING_PACKAGE("BeliefPropDecoder", "LDPCDecoders")) end return ext.BeliefPropDecoder(args...; kwargs...) end @@ -282,7 +285,7 @@ end function BitFlipDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordLDPCDecodersExt) if isnothing(ext) - throw(THROW_MISSING_LDPCDecoders) + throw(THROW_MISSING_PACKAGE("BitFlipDecoder", "LDPCDecoders")) end return ext.BitFlipDecoder(args...; kwargs...) end @@ -292,7 +295,7 @@ end function PyBeliefPropDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw(THROW_MISSING_PyQDecoders) + throw(THROW_MISSING_PACKAGE("PyBeliefPropDecoder","PyQDecoders")) end return ext.PyBeliefPropDecoder(args...; kwargs...) end @@ -301,7 +304,7 @@ end function PyBeliefPropOSDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw(THROW_MISSING_PyQDecoders) + throw(THROW_MISSING_PACKAGE("PyBeliefPropOSDecoder","PyQDecoders")) end return ext.PyBeliefPropOSDecoder(args...; kwargs...) end @@ -310,7 +313,7 @@ end function PyMatchingDecoder(args...; kwargs...) ext = Base.get_extension(QuantumClifford, :QuantumCliffordPyQDecodersExt) if isnothing(ext) - throw(THROW_MISSING_PyQDecoders) + throw(THROW_MISSING_PACKAGE("PyMatchingDecoder","PyQDecoders")) end return ext.PyMatchingDecoder(args...; kwargs...) end diff --git a/src/entanglement.jl b/src/entanglement.jl index b66dc2fdf..9d7c31826 100644 --- a/src/entanglement.jl +++ b/src/entanglement.jl @@ -152,7 +152,7 @@ function bigram(state::AbstractStabilizer; clip::Bool=true)::Matrix{Int} # JET-X for i in 1:rows l = findfirst(j->|(tab[i,j]...), 1:columns) r = findlast(j->|(tab[i,j]...), 1:columns) - (isnothing(l) || isnothing(r)) && throw(DomainError(THROW_INCONSISTENT_TABLEAU)) + (isnothing(l) || isnothing(r)) && throw(DomainError("The tableau is inconsistent (check if it is clip-canonicalized and Hermitian)")) bg[i, 1] = l bg[i, 2] = r end diff --git a/src/grouptableaux.jl b/src/grouptableaux.jl index 0d5df5e4c..c361a46cc 100644 --- a/src/grouptableaux.jl +++ b/src/grouptableaux.jl @@ -124,7 +124,7 @@ function groupify(s::Stabilizer; phases=false) # `Stabilizer` s), then multiply each one by a different subset of the elements in s to # create all 2ⁿ unique elements in the group generated by s, then return the `Tableau`. if phases == true - throw(ArgumentError(THROW_PHASE_FUNCTIONALITY_UNAVAILABLE_GROUPIFY)) + throw(ArgumentError("In groupify, the phases=true functionality is not yet implemented")) end gen_set = minimal_generating_set(s) n = length(gen_set)::Int diff --git a/src/linalg.jl b/src/linalg.jl index d7af24ac4..a0f2523bb 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -1,4 +1,8 @@ include("throws.jl") + +const THROW_BAD_DATA_STRUCTURE(type) = +"Using a `$type` type does not permit automatic tracking of the rank. +Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually." function permutesystems(c::CliffordOperator,p) # TODO this is a slow stupid implementation CliffordOperator(Tableau([tab(c)[i][p] for i in 1:2*nqubits(c)][vcat(p,p.+nqubits(c))])) end @@ -102,7 +106,7 @@ end function logdot(s1::Stabilizer, s2::Stabilizer) if nqubits(s1)!=length(s1) || nqubits(s2)!=length(s2) # TODO implement this - throw(DomainError(THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_DOTPROD)) + throw(DomainError("Only pure (not mixed) states are supported when calculating inner product.")) end if nqubits(s1)!=nqubits(s2) throw(DimensionMismatch(THROW_NQUBITS)) @@ -123,9 +127,9 @@ function logdot(s1::Stabilizer, s2::Stabilizer) return k end -LinearAlgebra.rank(s::Stabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE, +LinearAlgebra.rank(s::Stabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE("Stabilizer"), :rank, :Stabilizer)) -LinearAlgebra.rank(s::Destabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE, +LinearAlgebra.rank(s::Destabilizer) = throw(BadDataStructure(THROW_BAD_DATA_STRUCTURE("Destabilizer"), :rank, :Destabilizer)) LinearAlgebra.rank(s::MixedStabilizer) = s.rank LinearAlgebra.rank(s::MixedDestabilizer) = s.rank diff --git a/src/misc_ops.jl b/src/misc_ops.jl index 49444edbd..429e9974a 100644 --- a/src/misc_ops.jl +++ b/src/misc_ops.jl @@ -136,7 +136,8 @@ function applywstatus!(s::AbstractQCState, v::VerifyOp) # XXX It assumes the oth # TODO QuantumClifford should implement some submatrix comparison r,n = size(v.good_state) if(r!=n) - throw(ArgumentError(THROW_NOT_STABILIZER_STATE)) + throw(ArgumentError("""The argument you have provided for good_state is not a logical state within the codespace. +Expected a pure qubit stabilizer state (i.e. independent stabilizer generators on be equal to number of qubits)""")) end canonicalize_rref!(quantumstate(s),v.indices) # Document why rref is used sv = tab(s) diff --git a/src/nonclifford.jl b/src/nonclifford.jl index a72869adc..befabb046 100644 --- a/src/nonclifford.jl +++ b/src/nonclifford.jl @@ -43,7 +43,9 @@ end function GeneralizedStabilizer(state) n = nqubits(state) md = MixedDestabilizer(state) - rank(md)==n || throw(ArgumentError(THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_STABILIZER)) + rank(md)==n || throw(ArgumentError("""Attempting to convert a `Stabilizer`-like object to `GeneralizedStabilizer` object failed, +because the initial state does not represent a pure state. +Currently only pure states can be used to initialize a `GeneralizedStabilizer` mixture of stabilizer states.""")) GeneralizedStabilizer(md, DefaultDict(0.0im, (falses(n),falses(n))=>1.0+0.0im)) # TODO maybe it should default to Destabilizer, not MixedDestabilizer end @@ -365,7 +367,11 @@ struct PauliChannel{T,S} <: AbstractPauliChannel length(paulis) == length(weights) || throw(ArgumentError(THROW_BOUNDS)) n = nqubits(paulis[1][1]) for p in paulis - n == nqubits(p[1]) == nqubits(p[2]) || throw(ArgumentError(THROW_PAULI_BOUNDS)) + n == nqubits(p[1]) == nqubits(p[2]) || throw(ArgumentError(""" +You are attempting to construct a `PauliChannel` but have provided Pauli operators +that are not all of the same size (same number of qubits). +Please ensure that all of the Pauli operators being provided of of the same size. +""")) end new{typeof(paulis),typeof(weights)}(paulis,weights) end @@ -394,7 +400,8 @@ nqubits(pc::PauliChannel) = nqubits(pc.paulis[1][1]) See also: [`GeneralizedStabilizer`](@ref), [`PauliChannel`](@ref), [`UnitaryPauliChannel`](@ref) """ function apply!(state::GeneralizedStabilizer, gate::AbstractPauliChannel; prune_threshold=1e-10) - nqubits(state) == nqubits(gate) || throw(DimensionMismatch(THROW_EMBEDDING_REQUIRED)) + nqubits(state) == nqubits(gate) || throw(DimensionMismatch("The number of qubits in the GeneralizedStabilizer state does not match the number of qubits in the Pauli channel. + Use `embed` to pad the PauliChannel so it acts on the correct number of qubits.")) dict = state.destabweights stab = state.stab dtype = valtype(dict) diff --git a/src/project_trace_reset.jl b/src/project_trace_reset.jl index 9808da88e..4ce4954a7 100644 --- a/src/project_trace_reset.jl +++ b/src/project_trace_reset.jl @@ -1,4 +1,6 @@ include("throws.jl") +const THROW_CONSISTENT_QUBIT_SIZE = "`qubits` and `newstate` have to be of consistent size" +const THROW_SMALL_STABILIZER = "the stabilizer is not big enough to contain the new state" """ Generate a Pauli operator by using operators from a given the Stabilizer. @@ -350,7 +352,8 @@ function _project!(d::Destabilizer,pauli::PauliOperator;keep_result::Val{Bkr}=Va end if anticommutes == 0 if n != nqubits(stabilizer) - throw(BadDataStructure(THROW_INEFFICIENT_DESTABILIZER, + throw(BadDataStructure("`Destabilizer` can not efficiently (faster than n^3) detect whether you are projecting on a stabilized or a logical operator. +Switch to one of the `Mixed*` data structures.", :project!, :Destabilizer)) end @@ -674,8 +677,8 @@ These qubits are traced out first, which could lead to "nonlocal" changes in the tableau. """ function reset_qubits!(s::Stabilizer, newstate, qubits; phases=true) - nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_NQUBITS)) - length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_SIZE)) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_CONSISTENT_QUBIT_SIZE)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_SMALL_STABILIZER)) n = nqubits(s) s, x, z = canonicalize!(s,ranks=true) # TODO this is unnecessary, but it provides for nicely formatted tableaux; consider removing it for speed reasons _, rref_i = canonicalize_rref!((@view s[1:z]),qubits,phases=phases) @@ -692,8 +695,8 @@ end $TYPEDSIGNATURES """ function reset_qubits!(s::MixedStabilizer, newstate, qubits; phases=true) # TODO create the necessary interfaces so that Stabilizer and MixedStabilizer share this code - nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_NQUBITS)) - length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_BOUNDS)) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_CONSISTENT_QUBIT_SIZE)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_SMALL_STABILIZER)) n = nqubits(s) sv = stabilizerview(s) sv, rref_i = canonicalize_rref!(sv,qubits,phases=phases) @@ -709,8 +712,8 @@ $TYPEDSIGNATURES """ function reset_qubits!(s::MixedDestabilizer, newstate::AbstractStabilizer, qubits; phases=true) # TODO this is really inefficient _phases = Val(phases) - nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_SIZE)) - length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_BOUNDS)) + nqubits(newstate)==length(qubits) || throw(DimensionMismatch(THROW_CONSISTENT_QUBIT_SIZE)) + length(qubits) <= nqubits(s) || throw(DimensionMismatch(THROW_SMALL_STABILIZER)) newstatestab = stabilizerview(newstate) traceout!(s,qubits) for pauli in newstatestab diff --git a/src/symbolic_cliffords.jl b/src/symbolic_cliffords.jl index 07f269f8e..2fa1942bf 100644 --- a/src/symbolic_cliffords.jl +++ b/src/symbolic_cliffords.jl @@ -1,5 +1,13 @@ using Random: AbstractRNG, GLOBAL_RNG include("throws.jl") + +THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR(n, operator_with_size) = +"Set `n=$n` as a $operator_with_size being compacted (`compact=true`) has to result in a $n x $n `CliffordOperator`." + +THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION(operator_with_size) = +"Set a larger `n`, otherwise the `operator_with_size` can not fit in the allocated `CliffordOperator`. + Use `compact=true` if you want to discard the target index." + """Supertype of all symbolic operators. Subtype of `AbstractCliffordOperator`""" abstract type AbstractSymbolicOperator <: AbstractCliffordOperator end """Supertype of all single-qubit symbolic operators.""" @@ -223,7 +231,7 @@ function SingleQubitOperator(o::SingleQubitOperator, qubit::Int) return SingleQubitOperator(qubit, o.xx, o.xz, o.zx, o.zz, o.px, o.pz) end function SingleQubitOperator(op::CliffordOperator, qubit) - nqubits(op)==1 || throw(DimensionMismatch(THROW_INVALID_CONVERSION_TO_SINGLEQUBIT)) + nqubits(op)==1 || throw(DimensionMismatch("You are trying to convert a multiqubit `CliffordOperator` into a symbolic `SingleQubitOperator`.")) SingleQubitOperator(qubit,tab(op)[1,1]...,tab(op)[2,1]...,(~).(iszero.(tab(op).phases))...) end SingleQubitOperator(op::CliffordOperator) = SingleQubitOperator(op, 1) @@ -231,10 +239,10 @@ SingleQubitOperator(op::CliffordOperator) = SingleQubitOperator(op, 1) CliffordOperator(op::AbstractSingleQubitOperator, n; kw...) = CliffordOperator(SingleQubitOperator(op), n; kw...) function CliffordOperator(op::SingleQubitOperator, n; compact=false) if compact - n==1 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR)) + n==1 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR(1, "SingleQubitOperator"))) return CliffordOperator(Tableau([op.px ? 0x2 : 0x0, op.pz ? 0x2 : 0x0],[op.xx op.xz; op.zx op.zz])) else - n >= op.q || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION)) + n >= op.q || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION("SingleQubitOperator"))) c = one(CliffordOperator, n) c[op.q,op.q] = op.xx, op.xz # TODO define an `embed` helper function c[n+op.q,op.q] = op.zx, op.zz @@ -346,7 +354,7 @@ macro qubitop2(name, kernel, inv_kernel) struct $(esc(prefixname)) <: AbstractTwoQubitOperator q1::Int q2::Int - $(esc(prefixname))(q1,q2) = if q1<=0 || q2<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) elseif q1==q2 throw(ArgumentError(THROW_INVALID_TWO_QUBIT_GATE)) else new(q1,q2) end + $(esc(prefixname))(q1,q2) = if q1<=0 || q2<=0 throw(ArgumentError(THROW_NO_ZERO_QUBIT)) elseif q1==q2 throw(ArgumentError("Failed to create a two qubit gate because the two qubits it acts on have the same index. The qubit indices have to be different.")) else new(q1,q2) end end @doc $docstring $prefixname @inline $(esc(:qubit_kernel))(::$prefixname, x1, z1, x2, z2) = $kernel @@ -407,10 +415,10 @@ Then we can use a truth-table to boolean formula converter, e.g. https://www.dco function CliffordOperator(op::AbstractTwoQubitOperator, n; compact=false) if compact - n==2 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR)) + n==2 || throw(ArgumentError(THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR(2, "TwoQubitOperator"))) return CliffordOperator(typeof(op)) else - n >= max(op.q1,op.q2) || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION)) + n >= max(op.q1,op.q2) || throw(DimensionMismatch(THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION("TwoQubitOperator"))) c = one(CliffordOperator, n) _c = CliffordOperator(typeof(op)) for (i,q) in ((1,op.q1),(2,op.q2)) diff --git a/src/throws.jl b/src/throws.jl index 2a7768c9b..61426279f 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -11,178 +11,22 @@ const THROW_NQUBITS = "Unable to perform the requested operation due to encountering a mismatch \ between the number of qubits in the provided arguments." -const THROW_REPR_NEEDS_COMMUTATIVE_ALGEBRA = -"The group algebra must be commutative when using a single `repr` function,\ -which is not the case here. Please specify separate `A_repr` and `B_repr` \ -instead of a single `repr`. The default choice of\ -`A_repr=right_repr_matrix, B_repr=left_repr_matrix` is frequently sufficient." - -const THROW_MUST_BE_DIVISIBLE_BY_3 = -"The input parameters must be divisible by 3" - -const THROW_REQUIRED_POSITIVE_ARG = -"The input parameter should be positive" - const THROW_INVALID_XZ_COMPONENTS = "`xzcomponents` should be `:split` or `:together`" -const THROW_INVALID_CODE_DIMENSION = -"Dimension of the input code must be at least 2" - -const THROW_INVALID_X_METACHECKS = -"`X`-metachecks (`Mx`) require `D ≥ 4`" - -const THROW_INVALID_Z_METACHECKS = -"`Z`-metachecks (`Mz`) require `D ≥ 3`" - - -const THROW_INVALID_CUDA_ARG = -"First argument to @run_cuda should be a function call" - -const THROW_MODEL_MEMORY_LIMIT = -"Model exceeded memory limits" - -const THROW_MODEL_TIME_LIMIT = -"Model exceeded time limit" - -const THROW_INVALID_PARAMETERS_GOLAY = -"Invalid parameters: `n` must be either 24 or 23 to obtain a valid code." - -const THROW_INVALID_PARAMETERS_HAMMING = -"Invalid parameters: `r` must be ≥ 2 to obtain a valid code." const THROW_INVALID_PARAMETERS_REEDMULLER = "Invalid parameters: r must be non-negative and r ≤ m in order to valid code." -const THROW_COLOR_CODES_ODD = -"Only odd distance triangular color codes are allowed.\nRefer to https://arxiv.org/abs/1108.5738" - -const THROW_COLOR_CODES_MIN_DIST = -"Smallest allowed distance is 3.\nRefer to https://arxiv.org/abs/1108.5738" - -const THROW_DELFOSSE_823_MIN_BLOCKS = -"The number of blocks must be at least 1 to construct a valid code." - const THROW_DELFOSSE_MIN_BLOCKS = "The number of blocks must be at least 2 to construct a valid code." -const THROW_DELFOSSE_SELF_ORTHOGONAL = -"The `Reed-Muller` parity check matrix must be 'self-orthogonal' to construct a self-dual -CSS `DelfosseReichardt` code. Use `search_self_orthogonal_rm_codes` to search for good parameters for `Reed-Muller` codes -that provide `self-orthogonal` seeds." - -const THROW_DELFOSSE_REP_MULTIPLE = -"The number of blocks must be a multiple of 2." - -const THROW_INVALID_QUANTUM_REED_MULLER = -"Invalid parameters: m must be bigger than 2 in order to have a valid code." - -const THROW_INVALID_PARAMETERS_TILLICH_ZEMOR = -"Conditions for the existence of `M` in `H = [C | M]` are not satisfied." - -const THROW_INVALID_PARAMETERS_CLIFFORD = -"Input tableau should be of size 2n×n (top half is the X mappings and the bottom half are the Z mappings)." - const THROW_INVALID_ACTION_QUBITS = "The tableau and the provided operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error." -const THROW_INVALID_PARAMETERS_BCH_ARG = -"""Conditions for valid BCH(m, t) arguments: -- m ≥ 3 -- t < 2ᵐ⁻¹ -- m*t ≤ 2ᵐ - 1 -""" - -const THROW_MISSING_HECKE = -"You've invoked a function which depends on the package `Hecke` but you have not installed or imported it yet. -Immediately after you import `Hecke`, the function will be available." - -const THROW_MISSING_OSCAR = -"You've invoked a function which depends on the package `Oscar` but you have not installed or imported it yet. -Immediately after you import `Oscar`, the function will be available." - -const THROW_MISSING_LDPCDecoders = -"You've invoked a function which depends on the package `LDPCDecoders` but you have not installed or imported it yet. -Immediately after you import `LDPCDecoders`, the function will be available." - -const THROW_MISSING_PyQDecoders = -"You've invoked a function which depends on the package `PyQDecoders` but you have not installed or imported it yet. -Immediately after you import `PyQDecoders`, the function will be available." - -const THROW_INVALID_PARAMETERS_NOISE = -"The input noise should be between 0 and 1." - -const THROW_INVALID_LOGICAL_OPERATOR = -"`logical_operator_type` must be :X or :Z" - -const THROW_CHECKS_MISSING = -"Codes of the type used do not have separate X and Z parity checks, either because they are not a CSS code -and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library." - -const THROW_INCONSISTENT_TABLEAU = -"the tableau is inconsistent (check if it is clip-canonicalized and Hermitian)" - -const THROW_PHASE_FUNCTIONALITY_UNAVAILABLE_GROUPIFY = -"in groupify phases=true functionality not yet implemented" - -const THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_DOTPROD = -"Only pure (not mixed) states are supported when calculating inner product." - -const THROW_BAD_DATA_STRUCTURE = -"You've used a type(`Stabilizer` or `Destabilizer`) does not permit automatic tracking of the rank. -Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually." - -const THROW_NOT_STABILIZER_STATE = -"""The argument you have provided for good_state is not a logical state within the codespace. -Expected a pure qubit stabilizer state (i.e. independent stabilizer generators on be equal to number of qubits)""" - -const THROW_MIXED_FUNCTIONALITY_UNAVAILABLE_STABILIZER = -"""Attempting to convert a `Stabilizer`-like object to `GeneralizedStabilizer` object failed, -because the initial state does not represent a pure state. -Currently only pure states can be used to initialize a `GeneralizedStabilizer` mixture of stabilizer states.""" - -const THROW_PAULI_BOUNDS = -""" -You are attempting to construct a `PauliChannel` but have provided Pauli operators -that are not all of the same size (same number of qubits). -Please ensure that all of the Pauli operators being provided of of the same size. -""" - -const THROW_EMBEDDING_REQUIRED = -"The number of qubits in the GeneralizedStabilizer state does not match the number of qubits in the Pauli channel. - Use `embed` to pad the PauliChannel so it acts on the correct number of qubits." - -const THROW_INEFFICIENT_DESTABILIZER = -"`Destabilizer` can not efficiently (faster than n^3) detect whether you are projecting on a stabilized or a logical operator. -Switch to one of the `Mixed*` data structures." - -const THROW_ONLY_FULL_RANK_DESTABILIZER_SUPPORTED = -"Only full-rank `Destabilizer` can be converted to `MixedDestabilizer` with specific rank. Try not specifying `r`." - -const THROW_PHASES = -"Only {±1,±i} are permitted as phases." - -const THROW_ROW_MISMATCH_TABLEAUX = -"All input Tableaux/Stabilizers musT have the same number of rows." - const THROW_NO_ZERO_QUBIT = "Qubit indices have to be larger than zero, but you are attempting to create a gate acting on a qubit with a non-positive index. Ensure indexing always starts from 1." -const THROW_INVALID_CONVERSION_TO_SINGLEQUBIT = -"You are trying to convert a multiqubit `CliffordOperator` into a symbolic `SingleQubitOperator`." - -const THROW_INVALID_QUBIT_OPERATOR_SIZE_ALLOCATION = -"Set a larger `n`, otherwise the `SingleQubitOperator` or `TwoQubitOperator`(whichever is being used) can not fit in the allocated `CliffordOperator`. - Use `compact=true` if you want to discard the target index." - -const THROW_INVALID_TWO_QUBIT_GATE = -"Failed to create a two qubit gate because the two qubits it acts on have the same index. The qubit indices have to be different." - -const THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR = -"Set `n=k` when compacting (`compact=true`) a `k`-qubit operator, so that it results in a `k×k` `CliffordOperator`." - -const THROW_INVALID_BASIS_REP = -"`basis` should be one of :X, :Y, or :Z" diff --git a/src/useful_states.jl b/src/useful_states.jl index 5d37fe225..de5536e1c 100644 --- a/src/useful_states.jl +++ b/src/useful_states.jl @@ -29,7 +29,7 @@ function Base.one(::Type{T}, n; basis=:Z) where {T<:Tableau}# TODO support `basi elseif basis==:Z T(falses(n,n),LinearAlgebra.I(n)) else - throw(ArgumentError(THROW_INVALID_BASIS_REP)) + throw(ArgumentError("`basis` should be one of :X, :Y, or :Z")) end end Base.one(::Type{<:Stabilizer}, n; basis=:Z) = Stabilizer(one(Tableau,n; basis)) # TODO make it type preserving From 79308002803481cd4a520564022bd3ef2dadeeb2 Mon Sep 17 00:00:00 2001 From: Niranjan Nagumalli Date: Mon, 18 Aug 2025 02:22:57 +0530 Subject: [PATCH 11/11] refactor: fix throw_missing_package error by making throws.jl a module --- .../QuantumCliffordHeckeExt.jl | 1 + .../QuantumCliffordJuMPExt.jl | 1 + .../QuantumCliffordKAExt.jl | 2 ++ .../QuantumCliffordMakieExt.jl | 7 +++-- .../QuantumCliffordPlotsExt.jl | 3 ++- lib/QECCore/src/QECCore.jl | 1 + .../codes/quantum/delfosse_reichardt_code.jl | 2 +- .../quantum/delfosse_reichardt_repcode.jl | 2 +- src/QuantumClifford.jl | 6 ++--- src/dense_cliffords.jl | 1 - src/ecc/ECC.jl | 7 +++-- src/grouptableaux.jl | 1 - src/linalg.jl | 2 -- src/misc_ops.jl | 1 - src/mul_leftright.jl | 1 - src/nonclifford.jl | 1 - src/project_trace_reset.jl | 1 - src/symbolic_cliffords.jl | 1 - src/throws.jl | 26 ++++++++++++++----- src/useful_states.jl | 1 - 20 files changed, 38 insertions(+), 30 deletions(-) diff --git a/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl b/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl index 275a21a2c..0f61cbf4d 100644 --- a/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl +++ b/ext/QuantumCliffordHeckeExt/QuantumCliffordHeckeExt.jl @@ -32,5 +32,6 @@ include("lifted.jl") include("lacross.jl") include("lifted_product.jl") include("../../src/throws.jl") +using .Throws end # module diff --git a/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl b/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl index 3e7206e18..75d02237d 100644 --- a/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl +++ b/ext/QuantumCliffordJuMPExt/QuantumCliffordJuMPExt.jl @@ -25,5 +25,6 @@ export distance include("min_distance_mixed_integer_programming.jl") include("../../src/throws.jl") +using .Throws end diff --git a/ext/QuantumCliffordKAExt/QuantumCliffordKAExt.jl b/ext/QuantumCliffordKAExt/QuantumCliffordKAExt.jl index daf6adbb1..90b8d9be4 100644 --- a/ext/QuantumCliffordKAExt/QuantumCliffordKAExt.jl +++ b/ext/QuantumCliffordKAExt/QuantumCliffordKAExt.jl @@ -8,5 +8,7 @@ include("../../src/throws.jl") include("utilities.jl") include("mul_leftright.jl") +using .Throws + end #=============================================================================# diff --git a/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl b/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl index 30912329a..0a776f89e 100644 --- a/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl +++ b/ext/QuantumCliffordMakieExt/QuantumCliffordMakieExt.jl @@ -1,9 +1,12 @@ module QuantumCliffordMakieExt +include("../../src/throws.jl") + +using .Throws using Makie using QuantumClifford import QuantumClifford: stabilizerplot, stabilizerplot_axis -include("../../src/throws.jl") + # If you want to directly use heatmap function Makie.convert_arguments(P::Type{<:Makie.Heatmap}, s::Stabilizer) @@ -39,7 +42,7 @@ function Makie.plot!(myplot::StabilizerPlot) h = QuantumClifford.stab_to_gf2(s) h[:,1:end÷2] + h[:,end÷2+1:end]*2 else - throw(ErrorException(THROW_INVALID_XZ_COMPONENTS)) + throw(ErrorException("`xzcomponents` should be `:split` or `:together`")) end r = r[end:-1:1,:]' hm = Makie.heatmap!(myplot, r; diff --git a/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl b/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl index 7487af6d2..43563d3a0 100644 --- a/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl +++ b/ext/QuantumCliffordPlotsExt/QuantumCliffordPlotsExt.jl @@ -3,6 +3,7 @@ module QuantumCliffordPlotsExt using Plots using QuantumClifford include("../../src/throws.jl") +using .Throws @recipe function f(s::QuantumClifford.Stabilizer; xzcomponents=:together) seriestype := :heatmap @@ -22,7 +23,7 @@ include("../../src/throws.jl") h = QuantumClifford.stab_to_gf2(s) h[:,1:end÷2] + h[:,end÷2+1:end]*2 else - throw(ErrorException(THROW_INVALID_XZ_COMPONENTS)) + throw(ErrorException("`xzcomponents` should be `:split` or `:together`")) end end diff --git a/lib/QECCore/src/QECCore.jl b/lib/QECCore/src/QECCore.jl index 79f257dbe..2716e043d 100644 --- a/lib/QECCore/src/QECCore.jl +++ b/lib/QECCore/src/QECCore.jl @@ -59,6 +59,7 @@ include("codes/quantum/delfosse_reichardt_repcode.jl") include("codes/quantum/delfosse_reichardt_823_code.jl") include("../../../src/throws.jl") +using .Throws function __init__() if isdefined(Base.Experimental, :register_error_hint) diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl index 0d503439c..38e1e8efe 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_code.jl @@ -86,7 +86,7 @@ struct DelfosseReichardt <: AbstractCSSCode """The log-length of the classical Reed-Muller code.""" m::Int function DelfosseReichardt(p,r,m) - p < 2 && throw(ArgumentError(THROW_DELFOSSE_MIN_BLOCKS)) + p < 2 && throw(ArgumentError("The number of blocks must be at least 2 to construct a valid code.")) if r < 0 || r > m throw(ArgumentError(THROW_INVALID_PARAMETERS_REEDMULLER)) end diff --git a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl index c072acd99..32c5e1d3e 100644 --- a/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl +++ b/lib/QECCore/src/codes/quantum/delfosse_reichardt_repcode.jl @@ -57,7 +57,7 @@ struct DelfosseReichardtRepCode <: AbstractCSSCode """The number of blocks in the Delfosse-Reichardt Repetition code.""" p::Int function DelfosseReichardtRepCode(p) - p < 2 && throw(ArgumentError(THROW_DELFOSSE_MIN_BLOCKS)) + p < 2 && throw(ArgumentError("The number of blocks must be at least 2 to construct a valid code.")) p % 2 != 0 && throw(ArgumentError("The number of blocks must be a multiple of 2.")) new(p) end diff --git a/src/QuantumClifford.jl b/src/QuantumClifford.jl index 30a60dac6..943076b6e 100644 --- a/src/QuantumClifford.jl +++ b/src/QuantumClifford.jl @@ -105,10 +105,6 @@ const BIG_INT_MINUS_ONE = Ref{BigInt}() const BIG_INT_TWO = Ref{BigInt}() const BIG_INT_FOUR = Ref{BigInt}() -THROW_MISSING_PACKAGE(func, pack) = -"You've invoked `$func` which depends on the package `$pack` but you have not installed or imported it yet. -Immediately after you import `$pack`, the $func will be available." - function __init__() BIG_INT_MINUS_ONE[] = BigInt(-1) BIG_INT_TWO[] = BigInt(2) @@ -1467,4 +1463,6 @@ include("plotting_extensions.jl") include("gpu_adapters.jl") include("throws.jl") +using .Throws + end #module diff --git a/src/dense_cliffords.jl b/src/dense_cliffords.jl index 52d0e72f1..9b17285fc 100644 --- a/src/dense_cliffords.jl +++ b/src/dense_cliffords.jl @@ -1,4 +1,3 @@ -include("throws.jl") """ Clifford Operator specified by the mapping of the basis generators. diff --git a/src/ecc/ECC.jl b/src/ecc/ECC.jl index aa7973aa7..9f9a12de2 100644 --- a/src/ecc/ECC.jl +++ b/src/ecc/ECC.jl @@ -54,9 +54,6 @@ Only CSS codes have this method. See also: [`parity_checks`](@ref)""" -const THROW_CHECKS_MISSING(code) = -"Codes of the type $code do not have separate X and Z parity checks, either because they are not a CSS code -and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library." function parity_matrix_x(code::AbstractECC) throw(THROW_CHECKS_MISSING(code)) @@ -395,7 +392,9 @@ function isdegenerate(H::Stabilizer, d::Int=1) return isdegenerate(H, errors) end -include("../throws.jl") +include("../../src/throws.jl") +using .Throws + include("circuits.jl") include("decoder_pipeline.jl") diff --git a/src/grouptableaux.jl b/src/grouptableaux.jl index c361a46cc..991b2bdbb 100644 --- a/src/grouptableaux.jl +++ b/src/grouptableaux.jl @@ -1,4 +1,3 @@ -include("throws.jl") """ A tableau representation of the non-commutative canonical form of a set of Paulis, which is used in [`commutify`](@ref). diff --git a/src/linalg.jl b/src/linalg.jl index a0f2523bb..5e7ee7b4f 100644 --- a/src/linalg.jl +++ b/src/linalg.jl @@ -1,5 +1,3 @@ -include("throws.jl") - const THROW_BAD_DATA_STRUCTURE(type) = "Using a `$type` type does not permit automatic tracking of the rank. Use `length`, `trusted_rank`, the `MixedDestabilizer` type, or track the rank manually." diff --git a/src/misc_ops.jl b/src/misc_ops.jl index 429e9974a..9dcc8d926 100644 --- a/src/misc_ops.jl +++ b/src/misc_ops.jl @@ -1,5 +1,4 @@ import QuantumInterface: nsubsystems -include("throws.jl") """A Stabilizer measurement on the entirety of the quantum register. `projectrand!(state, pauli)` and `apply!(state, PauliMeasurement(pauli))` give the same (possibly non-deterministic) result. diff --git a/src/mul_leftright.jl b/src/mul_leftright.jl index efb669fc2..fedd52896 100644 --- a/src/mul_leftright.jl +++ b/src/mul_leftright.jl @@ -1,7 +1,6 @@ # using LoopVectorization using HostCPUFeatures: pick_vector_width import SIMD -include("throws.jl") """Nonvectorized version of `mul_left!` used for unit tests.""" function _mul_left_nonvec!(r::AbstractVector{T}, l::AbstractVector{T}; phases::Bool=true) where T<:Unsigned diff --git a/src/nonclifford.jl b/src/nonclifford.jl index befabb046..5507dfa58 100644 --- a/src/nonclifford.jl +++ b/src/nonclifford.jl @@ -1,4 +1,3 @@ -include("throws.jl") """ $(TYPEDEF) diff --git a/src/project_trace_reset.jl b/src/project_trace_reset.jl index 4ce4954a7..a5a8afd23 100644 --- a/src/project_trace_reset.jl +++ b/src/project_trace_reset.jl @@ -1,4 +1,3 @@ -include("throws.jl") const THROW_CONSISTENT_QUBIT_SIZE = "`qubits` and `newstate` have to be of consistent size" const THROW_SMALL_STABILIZER = "the stabilizer is not big enough to contain the new state" """ diff --git a/src/symbolic_cliffords.jl b/src/symbolic_cliffords.jl index 2fa1942bf..d4abaf778 100644 --- a/src/symbolic_cliffords.jl +++ b/src/symbolic_cliffords.jl @@ -1,5 +1,4 @@ using Random: AbstractRNG, GLOBAL_RNG -include("throws.jl") THROW_COMPACT_QUBIT_OPERATOR_SHAPE_ERROR(n, operator_with_size) = "Set `n=$n` as a $operator_with_size being compacted (`compact=true`) has to result in a $n x $n `CliffordOperator`." diff --git a/src/throws.jl b/src/throws.jl index 61426279f..dd2f9df69 100644 --- a/src/throws.jl +++ b/src/throws.jl @@ -1,3 +1,14 @@ +module Throws + +export THROW_BOUNDS, + THROW_SIZE, + THROW_NQUBITS, + THROW_INVALID_PARAMETERS_REEDMULLER, + THROW_INVALID_ACTION_QUBITS, + THROW_NO_ZERO_QUBIT, + THROW_MISSING_PACKAGE, + THROW_CHECKS_MISSING + const THROW_BOUNDS = "Unable to perform the requested operation due to encountering a mismatch \ between the provided index(indices) and the pertinent size(s) of the other \ @@ -11,16 +22,9 @@ const THROW_NQUBITS = "Unable to perform the requested operation due to encountering a mismatch \ between the number of qubits in the provided arguments." -const THROW_INVALID_XZ_COMPONENTS = -"`xzcomponents` should be `:split` or `:together`" - - const THROW_INVALID_PARAMETERS_REEDMULLER = "Invalid parameters: r must be non-negative and r ≤ m in order to valid code." -const THROW_DELFOSSE_MIN_BLOCKS = -"The number of blocks must be at least 2 to construct a valid code." - const THROW_INVALID_ACTION_QUBITS = "The tableau and the provided operator need to act on the same number of qubits. Consider specifying an array of indices as a third argument to the `apply!` function to avoid this error." @@ -29,4 +33,12 @@ const THROW_NO_ZERO_QUBIT = "Qubit indices have to be larger than zero, but you are attempting to create a gate acting on a qubit with a non-positive index. Ensure indexing always starts from 1." +THROW_MISSING_PACKAGE(func, pack) = +"You've invoked `$func` which depends on the package `$pack` but you have not installed or imported it yet. +Immediately after you import `$pack`, the $func will be available." + +THROW_CHECKS_MISSING(code) = +"Codes of the type $code do not have separate X and Z parity checks, either because they are not a CSS code +and thus inherently do not have separate checks, or because its separate checks are not yet implemented in this library." +end \ No newline at end of file diff --git a/src/useful_states.jl b/src/useful_states.jl index de5536e1c..fd89d08db 100644 --- a/src/useful_states.jl +++ b/src/useful_states.jl @@ -1,4 +1,3 @@ -include("throws.jl") """A multiqubit operator corresponding to all identities except for Pauli Z at `i`. See also: [`sY`](@ref), [`sMY`](@ref)""" function single_z(n,i) p = zero(PauliOperator, n)