Skip to content

Commit

Permalink
add hat to all docs and make fcreate and fdestroy compat with `…
Browse files Browse the repository at this point in the history
…qutip`
  • Loading branch information
ytdHuang committed Sep 17, 2024
1 parent b40c82c commit ad67360
Show file tree
Hide file tree
Showing 12 changed files with 85 additions and 68 deletions.
30 changes: 15 additions & 15 deletions docs/src/users_guide/states_and_operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ and then create a lowering operator ``\hat{a}`` corresponding to `5` number stat
a = destroy(5)
```

Now lets apply the lowering operator `a` to our vacuum state `vac`:
Now lets apply the lowering operator `\hat{a}` to our vacuum state `vac`:

```@example states_and_operators
a * vac
Expand Down Expand Up @@ -51,7 +51,7 @@ or just taking the square of the raising operator ``\left(\hat{a}^\dagger\right)
ad^2 * vac
```

Applying the raising operator twice gives the expected ``\sqrt{n+1}`` dependence. We can use the product of ``a^\dagger a`` to also apply the number operator to the state vector `vac`:
Applying the raising operator twice gives the expected ``\sqrt{n+1}`` dependence. We can use the product of ``\hat{a}^\dagger \hat{a}`` to also apply the number operator to the state vector `vac`:

```@example states_and_operators
ad * a * vac
Expand All @@ -69,7 +69,7 @@ or on the ``|2\rangle`` state:
ad * a * (ad^2 * vac)
```

Notice how in this last example, application of the number operator does not give the expected value ``n=2``, but rather ``2\sqrt{2}``. This is because this last state is not normalized to unity as ``a^\dagger|n\rangle=\sqrt{n+1}|n+1\rangle``. Therefore, we should [`normalize`](@ref) (or use [`unit`](@ref)) our vector first:
Notice how in this last example, application of the number operator does not give the expected value ``n=2``, but rather ``2\sqrt{2}``. This is because this last state is not normalized to unity as ``\hat{a}^\dagger|n\rangle=\sqrt{n+1}|n+1\rangle``. Therefore, we should [`normalize`](@ref) (or use [`unit`](@ref)) our vector first:

```@example states_and_operators
ad * a * normalize(ad^2 * vac)
Expand Down Expand Up @@ -204,13 +204,13 @@ At this stage, there is no difference. This should not be surprising as we calle
create(2) * vac
```

For a spin system, the operator analogous to the raising operator is the ``\sigma_+`` operator [`sigmap`](@ref). Applying on the spin state gives:
For a spin system, the operator analogous to the raising operator is the ``\hat{\sigma}_+`` operator [`sigmap`](@ref). Applying on the spin state gives:

```@example states_and_operators
sigmap() * spin
```

Now we see the difference! The [`sigmap`](@ref) operator acting on the spin state returns the zero vector. Why is this? To see what happened, let us use the [`sigmaz`](@ref) operator:
Now we see the difference! The [`sigmap`](@ref) operator acting on the spin state returns the zero vector. Why is this? To see what happened, let us use the ``\hat{\sigma}_z`` ([`sigmaz`](@ref)) operator:

```@example states_and_operators
sigmaz()
Expand All @@ -228,7 +228,7 @@ spin2 = basis(2, 1)
sigmaz() * spin2
```

The answer is now apparent. Since the `QuantumToolbox` [`sigmaz`](@ref) function uses the standard ``Z``-basis representation of the ``\sigma_z`` spin operator, the `spin` state corresponds to the ``|\uparrow\rangle`` state of a two-level spin system while `spin2` gives the ``|\downarrow\rangle`` state. Therefore, in our previous example `sigmap() * spin`, we raised the qubit state out of the truncated two-level Hilbert space resulting in the zero state.
The answer is now apparent. Since the `QuantumToolbox` [`sigmaz`](@ref) function uses the standard ``Z``-basis representation of the ``\hat{\sigma}_z`` spin operator, the `spin` state corresponds to the ``|\uparrow\rangle`` state of a two-level spin system while `spin2` gives the ``|\downarrow\rangle`` state. Therefore, in our previous example `sigmap() * spin`, we raised the qubit state out of the truncated two-level Hilbert space resulting in the zero state.

While at first glance this convention might seem somewhat odd, it is in fact quite handy. For one, the spin operators remain in the conventional form. Second, this corresponds nicely with the quantum information definitions of qubit states, where the excited ``|\uparrow\rangle`` state is label as ``|0\rangle``, and the ``|\downarrow\rangle`` state by ``|1\rangle``.

Expand Down Expand Up @@ -309,9 +309,9 @@ This support is based on the correspondence between linear operators acting on a
```math
\textrm{vec} : \mathcal{L}(\mathcal{H}) \rightarrow \mathcal{H}\otimes\mathcal{H}.
```
Therefore, a given density matrix ``\rho`` can then be vectorized, denoted as
Therefore, a given density matrix ``\hat{\rho}`` can then be vectorized, denoted as
```math
|\rho\rangle\rangle = \textrm{vec}(\rho).
|\hat{\rho}\rangle\rangle = \textrm{vec}(\hat{\rho}).
```

`QuantumToolbox` uses the column-stacking convention for the isomorphism between ``\mathcal{L}(\mathcal{H})`` and ``\mathcal{H}\otimes\mathcal{H}``. This isomorphism is implemented by the functions [`mat2vec`](@ref) and [`vec2mat`](@ref):
Expand All @@ -328,7 +328,7 @@ vec_rho = mat2vec(rho)
rho2 = vec2mat(vec_rho)
```

The `QuantumObject.type` attribute indicates whether a quantum object is a vector corresponding to an [`OperatorKet`](@ref), or its Hermitian conjugate [`OperatorBra`](@ref). One can also use [`isoperket`](@ref) and [`isoperbra`](@ref) to check the type:
The `QuantumObject.type` attribute indicates whether a quantum object is a vector corresponding to an [`OperatorKet`](@ref), or its Hermitian conjugate [`OperatorBra`](@ref). One can also use [`isoper`](@ref), [`isoperket`](@ref), and [`isoperbra`](@ref) to check the type:

```@example states_and_operators
println(isoper(vec_rho))
Expand All @@ -343,12 +343,12 @@ Because `Julia` is a column-oriented languages (like `Fortran` and `MATLAB`), in

```math
\begin{align}
A\rho~~~ &\rightarrow \textrm{spre}(A) * \textrm{vec}(\rho) = \mathbb{1}\otimes A ~ |\rho\rangle\rangle,\notag\\
\rho B &\rightarrow \textrm{spost}(B) * \textrm{vec}(\rho) = B^T\otimes \mathbb{1} ~ |\rho\rangle\rangle,\notag\\
A \rho B &\rightarrow \textrm{sprepost}(A,B) * \textrm{vec}(\rho) = B^T\otimes A ~ |\rho\rangle\rangle,\notag
\hat{A}\hat{\rho}~~~ &\rightarrow \textrm{spre}(\hat{A}) * \textrm{vec}(\hat{\rho}) = \hat{\mathbb{1}}\otimes \hat{A} ~ |\hat{\rho}\rangle\rangle,\notag\\
\hat{\rho} \hat{B} &\rightarrow \textrm{spost}(\hat{B}) * \textrm{vec}(\hat{\rho}) = \hat{B}^T\otimes \hat{\mathbb{1}} ~ |\hat{\rho}\rangle\rangle,\notag\\
\hat{A} \hat{\rho} \hat{B} &\rightarrow \textrm{sprepost}(\hat{A},\hat{B}) * \textrm{vec}(\hat{\rho}) = \hat{B}^T\otimes \hat{A} ~ |\hat{\rho}\rangle\rangle,\notag
\end{align}
```
where ``\mathbb{1}`` represents the identity operator with Hilbert space dimension equal to ``\rho``.
where ``\hat{\mathbb{1}}`` represents the identity operator with Hilbert space dimension equal to ``\hat{\rho}``.

```@example states_and_operators
A = Qobj([1 2; 3 4])
Expand All @@ -375,10 +375,10 @@ println(isoper(S_AB))
println(issuper(S_AB))
```

With the above definitions, the following equality holds in `Julia`:
With the above definitions, the following equalities hold in `Julia`:

```math
\textrm{vec}(A \rho B) = \textrm{spre}(A) * \textrm{spre}(B) * \textrm{vec}(\rho) = \textrm{sprepost}(A,B) * \textrm{vec}(\rho) ~~\forall~~A, B, \rho
\textrm{vec}(\hat{A} \hat{\rho} \hat{B}) = \textrm{spre}(\hat{A}) * \textrm{spre}(\hat{B}) * \textrm{vec}(\hat{\rho}) = \textrm{sprepost}(\hat{A},\hat{B}) * \textrm{vec}(\hat{\rho}) ~~\forall~~\hat{A}, \hat{B}, \hat{\rho}
```

```@example states_and_operators
Expand Down
8 changes: 4 additions & 4 deletions docs/src/users_guide/tensor.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ tensor(states...)
```
This state is slightly more complicated, describing two qubits in a superposition between the up and down states, while the third qubit is in its ground state.

To construct operators that act on an extended Hilbert space of a combined system, we similarly pass a list of operators for each component system to the [`tensor`](@ref) (or [`kron`](@ref)) function. For example, to form the operator that represents the simultaneous action of the ``\sigma_x`` operator on two qubits:
To construct operators that act on an extended Hilbert space of a combined system, we similarly pass a list of operators for each component system to the [`tensor`](@ref) (or [`kron`](@ref)) function. For example, to form the operator that represents the simultaneous action of the ``\hat{\sigma}_x`` operator on two qubits:

```@example tensor_products
tensor(sigmax(), sigmax())
```

To create operators in a combined Hilbert space that only act on a single component, we take the tensor product of the operator acting on the subspace of interest, with the identity operators corresponding to the components that are to be unchanged. For example, the operator that represents ``\sigma_z`` on the first qubit in a two-qubit system, while leaving the second qubit unaffected:
To create operators in a combined Hilbert space that only act on a single component, we take the tensor product of the operator acting on the subspace of interest, with the identity operators corresponding to the components that are to be unchanged. For example, the operator that represents ``\hat{\sigma}_z`` on the first qubit in a two-qubit system, while leaving the second qubit unaffected:

```@example tensor_products
tensor(sigmaz(), qeye(2))
Expand All @@ -61,7 +61,7 @@ The [`tensor`](@ref) (or [`kron`](@ref)) function is extensively used when const

### Two coupled qubits

First, let’s consider a system of two coupled qubits. Assume that both the qubits have equal energy splitting, and that the qubits are coupled through a ``\sigma_x \otimes \sigma_x`` interaction with strength ``g = 0.05`` (in units where the bare qubit energy splitting is unity). The Hamiltonian describing this system is:
First, let’s consider a system of two coupled qubits. Assume that both the qubits have equal energy splitting, and that the qubits are coupled through a ``\hat{\sigma}_x \otimes \hat{\sigma}_x`` interaction with strength ``g = 0.05`` (in units where the bare qubit energy splitting is unity). The Hamiltonian describing this system is:

```@example tensor_products
H = tensor(sigmaz(), qeye(2)) +
Expand All @@ -86,7 +86,7 @@ H = tensor(sigmaz(), qeye(2), qeye(2)) +
The simplest possible quantum mechanical description for light-matter interaction is encapsulated in the Jaynes-Cummings model, which describes the coupling between a two-level atom and a single-mode electromagnetic field (a cavity mode). Denoting the energy splitting of the atom and cavity ``\omega_a`` and ``\omega_c``, respectively, and the atom-cavity interaction strength ``g``, the Jaynes-Cummings Hamiltonian can be constructed as:

```math
H = \frac{\omega_a}{2}\sigma_z + \omega_c a^\dagger a + g (a^\dagger \sigma_- + a \sigma_+)
H = \frac{\omega_a}{2}\hat{\sigma}_z + \omega_c \hat{a}^\dagger \hat{a} + g (\hat{a}^\dagger \hat{\sigma}_- + \hat{a} \hat{\sigma}_+)
```

```@example tensor_products
Expand Down
4 changes: 2 additions & 2 deletions src/metrics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ entanglement(QO::QuantumObject, sel::Int) = entanglement(QO, (sel,))
tracedist(ρ::QuantumObject, σ::QuantumObject)
Calculates the [trace distance](https://en.wikipedia.org/wiki/Trace_distance) between two [`QuantumObject`](@ref):
``T(\rho, \sigma) = \frac{1}{2} \lVert \rho - \sigma \rVert_1``
``T(\hat{\rho}, \hat{\sigma}) = \frac{1}{2} \lVert \hat{\rho} - \hat{\sigma} \rVert_1``
Note that `ρ` and `σ` must be either [`Ket`](@ref) or [`Operator`](@ref).
"""
Expand All @@ -100,7 +100,7 @@ tracedist(
fidelity(ρ::QuantumObject, σ::QuantumObject)
Calculate the fidelity of two [`QuantumObject`](@ref):
``F(\rho, \sigma) = \textrm{Tr} \sqrt{\sqrt{\rho} \sigma \sqrt{\rho}}``
``F(\hat{\rho}, \hat{\sigma}) = \textrm{Tr} \sqrt{\sqrt{\hat{\rho}} \hat{\sigma} \sqrt{\hat{\rho}}}``
Here, the definition is from Nielsen & Chuang, "Quantum Computation and Quantum Information". It is the square root of the fidelity defined in R. Jozsa, Journal of Modern Optics, 41:12, 2315 (1994).
Expand Down
6 changes: 3 additions & 3 deletions src/negativity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ export negativity, partial_transpose
@doc raw"""
negativity(ρ::QuantumObject, subsys::Int; logarithmic::Bool=false)
Compute the [negativity](https://en.wikipedia.org/wiki/Negativity_(quantum_mechanics)) ``N(\rho) = \frac{\Vert \rho^{\Gamma}\Vert_1 - 1}{2}``
where ``\rho^{\Gamma}`` is the partial transpose of ``\rho`` with respect to the subsystem,
and ``\Vert X \Vert_1=\textrm{Tr}\sqrt{X^\dagger X}`` is the trace norm.
Compute the [negativity](https://en.wikipedia.org/wiki/Negativity_(quantum_mechanics)) ``N(\hat{\rho}) = \frac{\Vert \hat{\rho}^{\Gamma}\Vert_1 - 1}{2}``
where ``\hat{\rho}^{\Gamma}`` is the partial transpose of ``\hat{\rho}`` with respect to the subsystem,
and ``\Vert \hat{X} \Vert_1=\textrm{Tr}\sqrt{\hat{X}^\dagger \hat{X}}`` is the trace norm.
# Arguments
- `ρ::QuantumObject`: The density matrix (`ρ.type` must be [`OperatorQuantumObject`](@ref)).
Expand Down
6 changes: 3 additions & 3 deletions src/qobj/arithmetic_and_attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ end
@doc raw"""
dot(i::QuantumObject, A::QuantumObject j::QuantumObject)
Compute the generalized dot product `dot(i, A*j)` between three [`QuantumObject`](@ref): ``\langle i | A | j \rangle``
Compute the generalized dot product `dot(i, A*j)` between three [`QuantumObject`](@ref): ``\langle i | \hat{A} | j \rangle``
Supports the following inputs:
- `A` is in the type of [`Operator`](@ref), with `i` and `j` are both [`Ket`](@ref).
Expand Down Expand Up @@ -638,7 +638,7 @@ get_data(A::QuantumObject) = A.data
Get the coherence value ``\alpha`` by measuring the expectation value of the destruction operator ``\hat{a}`` on a state ``\ket{\psi}`` or a density matrix ``\hat{\rho}``.
It returns both ``\alpha`` and the corresponding state with the coherence removed: ``\ket{\delta_\alpha} = \exp ( \bar{\alpha} \hat{a} - \alpha \hat{a}^\dagger ) \ket{\psi}`` for a pure state, and ``\hat{\rho_\alpha} = \exp ( \bar{\alpha} \hat{a} - \alpha \hat{a}^\dagger ) \hat{\rho} \exp ( -\bar{\alpha} \hat{a} + \alpha \hat{a}^\dagger )`` for a density matrix. These states correspond to the quantum fluctuations around the coherent state ``\ket{\alpha}`` or ``\dyad{\alpha}``.
It returns both ``\alpha`` and the corresponding state with the coherence removed: ``\ket{\delta_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \ket{\psi}`` for a pure state, and ``\hat{\rho_\alpha} = \exp ( \alpha^* \hat{a} - \alpha \hat{a}^\dagger ) \hat{\rho} \exp ( -\bar{\alpha} \hat{a} + \alpha \hat{a}^\dagger )`` for a density matrix. These states correspond to the quantum fluctuations around the coherent state ``\ket{\alpha}`` or ``|\alpha\rangle\langle\alpha|``.
"""
function get_coherence::QuantumObject{<:AbstractArray,KetQuantumObject})
a = destroy(prod.dims))
Expand All @@ -665,7 +665,7 @@ Note that this method currently works for [`Ket`](@ref), [`Bra`](@ref), and [`Op
# Examples
If `order = [2, 1, 3]`, the Hilbert space structure will be re-arranged: H₁ ⊗ H₂ ⊗ H₃ → H₂ ⊗ H₁ ⊗ H₃.
If `order = [2, 1, 3]`, the Hilbert space structure will be re-arranged: ``\mathcal{H}_1 \otimes \mathcal{H}_2 \otimes \mathcal{H}_3 \rightarrow \mathcal{H}_2 \otimes \mathcal{H}_1 \otimes \mathcal{H}_3``.
```
julia> ψ1 = fock(2, 0)
Expand Down
Loading

0 comments on commit ad67360

Please sign in to comment.