Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utility functions for bosonic states #340

Open
labay11 opened this issue Dec 8, 2024 · 3 comments · May be fixed by #343
Open

Utility functions for bosonic states #340

labay11 opened this issue Dec 8, 2024 · 3 comments · May be fixed by #343
Labels
enhancement New feature or request

Comments

@labay11
Copy link

labay11 commented Dec 8, 2024

Problem Description

Define and correct some utility functions to get the mean photon number and coherence for bosonic systems.

In arithmetic_and_attributes.jl there is already a defined function to get the coherence for a quantum state. However, the current implementation is only valid for single systems. For composite systems the function computes an annihilation operator which is the product over all the dimensions, such definition is not correct as the total annihilation operator should be the kronecker product of a in each subsysems.

Proposed Solution

Here are some functions I use to calculate the mean photon number without the need to construct the operator. This is particularly faster for density matrix as you can skip the matrix product.

function mpn::QuantumObject{T,OperatorKetQuantumObject}) where {T}
    if length.dims) > 1
        throw(ArgumentError("Mean photon number not implemented for composite OPeratorKetQuantumObject"))
    end
    r = ρ.dims[1]
    return real(sum(ρ[(k-1)*r+k] * (k - 1) for k in 1:r))
end


function mpn::QuantumObject{T,KetQuantumObject}) where {T}
    if length.dims) == 1
        return real(mapreduce(k -> abs(ψ[k])^2 * (k - 1), +, 1:ρ.dims[1]))
    else
        R = CartesianIndices((ψ.dims...,))
        off = circshift.dims, 1)
        off[end] = 1

        x = 0.0im
        for j in R
            J = sum((Tuple(j) .- 1) .* off) + 1
            x += abs(ψ[J])^2 * prod(Tuple(j) .- 1)
        end
        return real(x)
    end
end

function mpn::QuantumObject{T,OperatorQuantumObject}) where {T}
    if length.dims) == 1
        return real(mapreduce(k -> abs(ρ[k, k]) * (k - 1), +, 1:ρ.dims[1]))
    else
        R = CartesianIndices((ρ.dims...,))
        off = circshift.dims, 1)
        off[end] = 1

        J = 1
        x = 0.0im
        for j in R
            # convert the cartesian index j into an array index J
            J = sum((Tuple(j) .- 1) .* off) + 1
            x += ρ[J, J] * prod(Tuple(j) .- 1)
        end
        return real(x)
    end
end

In the case of the get_coherent functions I would propose to divide into two functions: get_coherence which returns expect(a, *) and remove_coherence which returns the state with D' * ψ applied.

function get_coherence::QuantumObject{<:AbstractArray,KetQuantumObject,1})
    return mapreduce(n -> sqrt(n-1) * ψ.data[n] * conj.data[n-1]), +, 2:ψ.dims[1])
end

function get_coherence::QuantumObject{T,OperatorQuantumObject,1})
    return mapreduce(n -> sqrt(n-1) * ρ.data[n, n-1], +, 2:ψ.dims[1])
end

function remove_coherence::QuantumObject{<:AbstractArray,KetQuantumObject})
    α = get_coherence(ψ)
    a = mapreduce(dim -> destroy(dim), kron, ψ.dims)
    D = exp* a' - conj(α) * a)

    return D' * ρ * D
end

Similarly to the mpn functions I proposed, get_coherence can also be extended to multiple subsystems.

Alternate Solutions

No response

Additional Context

No response

@labay11 labay11 added the enhancement New feature or request label Dec 8, 2024
@albertomercurio
Copy link
Member

Hi @labay11,

Thank you for suggesting new features.

I like the idea of avoiding to define the bosonic operators when computing the coherence of the state, by directly iterating over the elements of the array. There are a few comments about the functions you defined.

Perhaps it is better to change the name of the mpn function to something more specific and readable. Maybe mean_occupation, or mean_population. I would avoid to use the photon word, because they represent generic bosons as phonons, magnons and many others. If you have other suggestions about the name, please write yours here.

Then, I would include the options to also choose for which subsystem we want to compute the mean occupation or the coherence. Immagine to have many bosons, and I only want to compute the coherence of the second one only, or the third and the fourth.

The definition of your mpn functions are very smart, even if I think we can improve them a bit. For example, we can use the @inbounds macro to avoid bounds checking when indexing over the array. Also, the following code should be a bit more efficient

x = sum(R) do j
    j_tuple = Tuple(j) .- 1
    J = dot(j_tuple, off) + 1
    abs2(ψ[J]) * prod(j_tuple)
end

and also the other implementations.

Overall, I think this is a good idea. Do you want to contribute with a Pull Request?

@ytdHuang
Copy link
Member

ytdHuang commented Dec 8, 2024

Does Python qutip also have a similar function ?

If it does, we can make the function name same as theirs.

@labay11
Copy link
Author

labay11 commented Dec 8, 2024

@albertomercurio I like the idea of being able to calculate the mean value in just one subsystem. Also the name mean_occupation sounds good to me.

@ytdHuang I think it is not implemented in QuTiP.

@labay11 labay11 linked a pull request Dec 8, 2024 that will close this issue
6 tasks
@ytdHuang ytdHuang linked a pull request Dec 9, 2024 that will close this issue
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants