diff --git a/CHANGELOG.md b/CHANGELOG.md index d4a8cfd7b..0cb957438 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://github.com/qutip/QuantumToolbox.jl/tree/main) +- Introduce `QuantumToolbox.settings` and `auto_tidyup`. ([#460]) + ## [v0.31.0] Release date: 2025-05-03 @@ -221,3 +223,4 @@ Release date: 2024-11-13 [#453]: https://github.com/qutip/QuantumToolbox.jl/issues/453 [#455]: https://github.com/qutip/QuantumToolbox.jl/issues/455 [#456]: https://github.com/qutip/QuantumToolbox.jl/issues/456 +[#460]: https://github.com/qutip/QuantumToolbox.jl/issues/460 diff --git a/docs/make.jl b/docs/make.jl index 21b051f04..218cf9653 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -64,6 +64,7 @@ const PAGES = [ "Hierarchical Equations of Motion" => "users_guide/HEOM.md", "Solving for Steady-State Solutions" => "users_guide/steadystate.md", "Two-time correlation functions" => "users_guide/two_time_corr_func.md", + "QuantumToolbox Settings" => "users_guide/settings.md", "Extensions" => [ "users_guide/extensions/cuda.md", "users_guide/extensions/cairomakie.md", diff --git a/docs/src/resources/api.md b/docs/src/resources/api.md index b9df5dbd9..0358ceb1d 100644 --- a/docs/src/resources/api.md +++ b/docs/src/resources/api.md @@ -299,6 +299,7 @@ AbstractLinearMap ## [Utility functions](@id doc-API:Utility-functions) ```@docs +QuantumToolbox.settings QuantumToolbox.versioninfo QuantumToolbox.about gaussian diff --git a/docs/src/users_guide/settings.md b/docs/src/users_guide/settings.md new file mode 100644 index 000000000..be8d914e9 --- /dev/null +++ b/docs/src/users_guide/settings.md @@ -0,0 +1,36 @@ +# [QuantumToolbox Settings](@id doc:QuantumToolbox-Settings) + +In this section, we introduce the default global settings used throughout the package and show how to modify them. + +All settings are stored in [`QuantumToolbox.settings`](@ref). + +!!! warning "Differences from QuTiP" + Due to the differences in programming languages, solving algorithms, and many other reasons, these global settings (including their default values and usage) may be very different from those in `Python QuTiP`. + +## List of settings + +Here, we list out each setting along with the specific functions that will use it. + +- `tidyup_tol::Float64 = 1e-14` : tolerance for [`tidyup`](@ref) and [`tidyup!`](@ref). +- `auto_tidyup::Bool = true` : Automatically tidyup during the following situations: + * Solving for eigenstates, including [`eigenstates`](@ref), [`eigsolve`](@ref), and [`eigsolve_al`](@ref). +- (to be announced) + +## Change default settings + +First, we can check the current [`QuantumToolbox.settings`](@ref): + +```@example settings +using QuantumToolbox + +QuantumToolbox.settings +``` + +Next, one can overwrite the default settings by + +```@example settings +QuantumToolbox.settings.tidyup_tol = 1e-10 +QuantumToolbox.settings.auto_tidyup = false + +QuantumToolbox.settings +``` \ No newline at end of file diff --git a/src/QuantumToolbox.jl b/src/QuantumToolbox.jl index 409bcfa54..40bfc245f 100644 --- a/src/QuantumToolbox.jl +++ b/src/QuantumToolbox.jl @@ -75,6 +75,7 @@ export permute export cache_operator, iscached, isconstant # Utility +include("settings.jl") include("utilities.jl") include("versioninfo.jl") include("progress_bar.jl") diff --git a/src/qobj/arithmetic_and_attributes.jl b/src/qobj/arithmetic_and_attributes.jl index 8eecc5acd..957ef786d 100644 --- a/src/qobj/arithmetic_and_attributes.jl +++ b/src/qobj/arithmetic_and_attributes.jl @@ -629,27 +629,28 @@ purity(ρ::QuantumObject{ObjType}) where {ObjType<:Union{Ket,Bra}} = sum(abs2, purity(ρ::QuantumObject{Operator}) = real(tr(ρ.data^2)) @doc raw""" - tidyup(A::QuantumObject, tol::Real=1e-14) + tidyup(A::QuantumObject, tol::Real=settings.tidyup_tol) Given a [`QuantumObject`](@ref) `A`, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than `tol`. """ -tidyup(A::QuantumObject, tol::T = 1e-14) where {T<:Real} = QuantumObject(tidyup(A.data, tol), A.type, A.dimensions) -tidyup(A::AbstractArray, tol::T2 = 1e-14) where {T2<:Real} = tidyup!(copy(A), tol) +tidyup(A::QuantumObject, tol::T = settings.tidyup_tol) where {T<:Real} = + QuantumObject(tidyup(A.data, tol), A.type, A.dimensions) +tidyup(A::AbstractArray, tol::T2 = settings.tidyup_tol) where {T2<:Real} = tidyup!(copy(A), tol) @doc raw""" - tidyup!(A::QuantumObject, tol::Real=1e-14) + tidyup!(A::QuantumObject, tol::Real=settings.tidyup_tol) Given a [`QuantumObject`](@ref) `A`, check the real and imaginary parts of each element separately. Remove the real or imaginary value if its absolute value is less than `tol`. Note that this function is an in-place version of [`tidyup`](@ref). """ -tidyup!(A::QuantumObject, tol::T = 1e-14) where {T<:Real} = (tidyup!(A.data, tol); A) -function tidyup!(A::AbstractSparseArray, tol::T2 = 1e-14) where {T2<:Real} +tidyup!(A::QuantumObject, tol::T = settings.tidyup_tol) where {T<:Real} = (tidyup!(A.data, tol); A) +function tidyup!(A::AbstractSparseArray, tol::T2 = settings.tidyup_tol) where {T2<:Real} tidyup!(nonzeros(A), tol) # tidyup A.nzval in-place (also support for CUDA sparse arrays) return dropzeros!(A) end -tidyup!(A::AbstractArray{T}, tol::T2 = 1e-14) where {T<:Real,T2<:Real} = @. A = T(abs(A) > tol) * A -tidyup!(A::AbstractArray{T}, tol::T2 = 1e-14) where {T,T2<:Real} = +tidyup!(A::AbstractArray{T}, tol::T2 = settings.tidyup_tol) where {T<:Real,T2<:Real} = @. A = T(abs(A) > tol) * A +tidyup!(A::AbstractArray{T}, tol::T2 = settings.tidyup_tol) where {T,T2<:Real} = @. A = T(abs(real(A)) > tol) * real(A) + 1im * T(abs(imag(A)) > tol) * imag(A) @doc raw""" diff --git a/src/qobj/eigsolve.jl b/src/qobj/eigsolve.jl index 1d8f256e3..856afa956 100644 --- a/src/qobj/eigsolve.jl +++ b/src/qobj/eigsolve.jl @@ -249,6 +249,7 @@ function _eigsolve( end mul!(cache1, Vₘ, M(Uₘ * VR)) vecs = cache1[:, 1:k] + settings.auto_tidyup && tidyup!(vecs) return EigsolveResult(vals, vecs, type, dimensions, iter, numops, (iter < maxiter)) end @@ -349,7 +350,10 @@ function eigsolve( vals = @. (1 + sigma * res.values) / res.values end - return EigsolveResult(vals, res.vectors, res.type, res.dimensions, res.iter, res.numops, res.converged) + vecs = res.vectors + settings.auto_tidyup && tidyup!(vecs) + + return EigsolveResult(vals, vecs, res.type, res.dimensions, res.iter, res.numops, res.converged) end @doc raw""" @@ -430,6 +434,8 @@ function eigsolve_al( @. vecs[:, i] = vec * exp(-1im * angle(vec[1])) end + settings.auto_tidyup && tidyup!(vecs) + return EigsolveResult(vals, vecs, res.type, res.dimensions, res.iter, res.numops, res.converged) end @@ -457,11 +463,11 @@ values: 2.8569700138728056 + 0.0im vectors: 5×5 Matrix{ComplexF64}: - 0.106101+0.0im -0.471249-0.0im … 0.471249-0.0im 0.106101-0.0im - -0.303127-0.0im 0.638838+0.0im 0.638838+0.0im 0.303127-0.0im - 0.537348+0.0im -0.279149-0.0im 0.279149-0.0im 0.537348-0.0im + 0.106101+0.0im -0.471249-0.0im … 0.471249+0.0im 0.106101+0.0im + -0.303127-0.0im 0.638838+0.0im 0.638838+0.0im 0.303127+0.0im + 0.537348+0.0im -0.279149-0.0im 0.279149+0.0im 0.537348+0.0im -0.638838-0.0im -0.303127-0.0im -0.303127-0.0im 0.638838+0.0im - 0.447214+0.0im 0.447214+0.0im -0.447214-0.0im 0.447214-0.0im + 0.447214+0.0im 0.447214+0.0im -0.447214-0.0im 0.447214+0.0im julia> expect(H, ψ[1]) ≈ E[1] true @@ -473,6 +479,7 @@ function LinearAlgebra.eigen(A::QuantumObject{OpType}; kwargs...) where {OpType< # This fixes a type inference issue. But doesn't work for GPU arrays E::mat2vec(to_dense(MT)) = F.values U::to_dense(MT) = F.vectors + settings.auto_tidyup && tidyup!(U) return EigsolveResult(E, U, A.type, A.dimensions, 0, 0, true) end diff --git a/src/settings.jl b/src/settings.jl new file mode 100644 index 000000000..b9be9b0b2 --- /dev/null +++ b/src/settings.jl @@ -0,0 +1,36 @@ +Base.@kwdef mutable struct Settings + tidyup_tol::Float64 = 1e-14 + auto_tidyup::Bool = true +end + +function Base.show(io::IO, s::Settings) + println(io, "QuantumToolbox.jl Settings") + println(io, "--------------------------") + map(x -> println(io, "$x = ", getfield(s, x)), fieldnames(Settings)) + return nothing +end + +@doc raw""" + QuantumToolbox.settings + +Contains all the default global settings of QuantumToolbox.jl. + +# List of settings + +- `tidyup_tol::Float64 = 1e-14` : tolerance for [`tidyup`](@ref) and [`tidyup!`](@ref). +- `auto_tidyup::Bool = true` : Automatically tidyup. + +For detailed explanation of each settings, see our documentation [here](https://qutip.org/QuantumToolbox.jl/stable/users_guide/settings). + +# Change default settings + +One can overwrite the default global settings by + +```julia +using QuantumToolbox + +QuantumToolbox.settings.tidyup_tol = 1e-10 +QuantumToolbox.settings.auto_tidyup = false +``` +""" +const settings = Settings()