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

Kraus Map Qobj #14

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
less bugs
  • Loading branch information
Ericgig committed Nov 19, 2024
commit 6ccac0835a39c607eaf46b332fae3e6badb8993d
5 changes: 5 additions & 0 deletions qutip/core/data/properties.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ cpdef bint isequal_dia(Dia A, Dia B, double atol=-1, double rtol=-1):
cdef double complex *ptr_b
cdef idxint size=A.shape[1]

if A.num_diag == 0:
return iszero_dia(B, atol)
if B.num_diag == 0:
return iszero_dia(A, atol)

# TODO:
# Works only for a sorted offsets list.
# We don't have a check for whether it's already sorted, but it should be
Expand Down
10 changes: 5 additions & 5 deletions qutip/core/dimensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,12 +811,12 @@ def __init__(self, from_: Space, to_: Space):
def from_prepost(pre, post):
pre = Dimensions(pre)
post = Dimensions(post)
return Dimensions([
SuperSpace(Dimensions([pre[1], post[0]])),
SuperSpace(Dimensions([pre[0], post[1]])),
])
return Dimensions(
SuperSpace(Dimensions(pre[1], post[0])),
SuperSpace(Dimensions(pre[0], post[1])),
)

def tr(self):
def transpose(self):
return Dimensions(self.to_, self.from_)

def __eq__(self, other: "Dimensions") -> bool:
Expand Down
2 changes: 2 additions & 0 deletions qutip/core/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ def _hilbert_space_dims(oper):
return oper.dims
elif oper.type == 'super' and oper.superrep in ['choi', 'chi', 'super']:
return [oper.dims[0][1], oper.dims[1][0]]
elif oper.type == 'super' and oper.superrep in ['kraus']:
return oper._pre_dims().as_list()
else:
raise TypeError('oper is not a valid quantum channel!')

Expand Down
98 changes: 4 additions & 94 deletions qutip/core/qobj/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,6 @@
from numpy.typing import ArrayLike


_NORM_FUNCTION_LOOKUP = {
'tr': _data.norm.trace,
'one': _data.norm.one,
'max': _data.norm.max,
'fro': _data.norm.frobenius,
'l2': _data.norm.l2,
}
_NORM_ALLOWED_MATRIX = {'tr', 'fro', 'one', 'max'}
_NORM_ALLOWED_VECTOR = {'l2', 'max'}


def _latex_real(x):
if not x:
return "0"
Expand Down Expand Up @@ -408,10 +397,10 @@ def _str_header(self):
f"dtype={self.dtype.__name__}",
])
# TODO: Should this be here?
# if self.type in ('oper', 'super'):
# out += ", isherm=" + str(self.isherm)
# if self.issuper and self.superrep != 'super':
# out += ", superrep=" + repr(self.superrep)
if self.type in ('oper', 'super'):
out += ", isherm=" + str(self.isherm)
if self.issuper and self.superrep != 'super':
out += ", superrep=" + repr(self.superrep)
return out

def __str__(self):
Expand Down Expand Up @@ -691,85 +680,6 @@ def tidyup(self, atol: float = None) -> Qobj:
self.data = _data.tidyup(self.data, atol)
return self

def norm(
self,
norm: Literal["l2", "max", "fro", "tr", "one"] = None,
kwargs: dict[str, Any] = None
) -> float:
"""
Norm of a quantum object.

Default norm is L2-norm for kets and trace-norm for operators. Other
ket and operator norms may be specified using the `norm` parameter.

Parameters
----------
norm : str
Which type of norm to use. Allowed values for vectors are 'l2' and
'max'. Allowed values for matrices are 'tr' for the trace norm,
'fro' for the Frobenius norm, 'one' and 'max'.

kwargs : dict
Additional keyword arguments to pass on to the relevant norm
solver. See details for each norm function in :mod:`.data.norm`.

Returns
-------
norm : float
The requested norm of the operator or state quantum object.
"""
if self.type in ('ket', 'bra'):
norm = norm or 'l2'
if norm not in _NORM_ALLOWED_VECTOR:
raise ValueError(
"vector norm must be in " + repr(_NORM_ALLOWED_VECTOR)
)
else:
norm = norm or 'tr'
if norm not in _NORM_ALLOWED_MATRIX:
raise ValueError(
"matrix norm must be in " + repr(_NORM_ALLOWED_MATRIX)
)

kwargs = kwargs or {}
return _NORM_FUNCTION_LOOKUP[norm](self._data, **kwargs)

def unit(
self,
inplace: bool = False,
norm: Literal["l2", "max", "fro", "tr", "one"] = None,
kwargs: dict[str, Any] = None
) -> Qobj:
"""
Operator or state normalized to unity. Uses norm from Qobj.norm().

Parameters
----------
inplace : bool
Do an in-place normalization
norm : str
Requested norm for states / operators.
kwargs : dict
Additional key-word arguments to be passed on to the relevant norm
function (see :meth:`.norm` for more details).

Returns
-------
obj : :class:`.Qobj`
Normalized quantum object. Will be the `self` object if in place.
"""
norm_ = self.norm(norm=norm, kwargs=kwargs)
if inplace:
self.data = _data.mul(self.data, 1 / norm_)
self.isherm = self._isherm if norm_.imag == 0 else None
self.isunitary = (self._isunitary
if abs(norm_) - 1 < settings.core['atol']
else None)
out = self
else:
out = self / norm_
return out

def transform(
self,
inpt: list[Qobj] | ArrayLike,
Expand Down
102 changes: 88 additions & 14 deletions qutip/core/qobj/_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
from .. import data as _data
from ..dimensions import enumerate_flat, collapse_dims_super
import warnings
from typing import Any, Literal


__all__ = []


_CALL_ALLOWED = {
('super', 'oper'),
('super', 'ket'),
('oper', 'ket'),
}


class Operator(Qobj):
def __init__(self, data, dims, **flags):
super().__init__(data, dims, **flags)
if self._dims.type not in ["oper"]:
raise ValueError(
f"Expected operator dimensions, but got {self._dims.type}"
)

@property
def isoper(self) -> bool:
return True
Expand Down Expand Up @@ -128,12 +128,8 @@ def __call__(self, other: Qobj) -> Qobj:
"""
if not isinstance(other, Qobj):
raise TypeError("Only defined for quantum objects.")
if (self.type, other.type) not in _CALL_ALLOWED:
if other.type not in ["ket"]:
raise TypeError(self.type + " cannot act on " + other.type)
if self.issuper:
if other.isket:
other = other.proj()
return qutip.vector_to_operator(self @ qutip.operator_to_vector(other))
return self.__matmul__(other)

def __pow__(self, n: int, m=None) -> Qobj:
Expand Down Expand Up @@ -502,7 +498,7 @@ def groundstate(
) -> tuple[float, Qobj]:
"""Ground state Eigenvalue and Eigenvector.

Defined for quantum operators or superoperators only.
Defined for quantum operators only.

Parameters
----------
Expand Down Expand Up @@ -601,6 +597,84 @@ def trunc_neg(self, method: Literal["clip", "sgs"] = "clip") -> Qobj:
out_data = _data.mul(out_data, 1/_data.norm.trace(out_data))
return Qobj(out_data, dims=self._dims, isherm=True, copy=False)

def norm(
self,
norm: Literal["max", "fro", "tr", "one"] = "tr",
kwargs: dict[str, Any] = None
) -> float:
"""
Norm of a quantum object.

Default norm is the trace-norm. Other operator norms may be
specified using the `norm` parameter.

Parameters
----------
norm : str, default: "tr"
Which type of norm to use. Allowed values are 'tr' for the trace
norm, 'fro' for the Frobenius norm, 'one' and 'max'.

kwargs : dict, optional
Additional keyword arguments to pass on to the relevant norm
solver. See details for each norm function in :mod:`.data.norm`.

Returns
-------
norm : float
The requested norm of the operator or state quantum object.
"""
norm = norm or "tr"
if norm not in {'tr', 'fro', 'one', 'max'}:
raise ValueError(
"matrix norm must be in {'tr', 'fro', 'one', 'max'}"
)

kwargs = kwargs or {}
return {
'tr': _data.norm.trace,
'one': _data.norm.one,
'max': _data.norm.max,
'fro': _data.norm.frobenius,
}[norm](self._data, **kwargs)

def unit(
self,
inplace: bool = False,
norm: Literal["l2", "max", "fro", "tr", "one"] = "tr",
kwargs: dict[str, Any] = None
) -> Qobj:
"""
Operator or state normalized to unity. Uses norm from Qobj.norm().

Parameters
----------
inplace : bool
Do an in-place normalization
norm : str
Requested norm for states / operators.
kwargs : dict
Additional key-word arguments to be passed on to the relevant norm
function (see :meth:`.norm` for more details).

Returns
-------
obj : :class:`.Qobj`
Normalized quantum object. Will be the `self` object if in place.
"""
norm_ = self.norm(norm=norm, kwargs=kwargs)
if inplace:
self.data = _data.mul(self.data, 1 / norm_)
self.isherm = self._isherm if norm_.imag == 0 else None
self.isunitary = (
self._isunitary
if abs(norm_) - 1 < settings.core['atol']
else None
)
out = self
else:
out = self / norm_
return out


class Scalar(Operator):
# Scalar can be anything
Expand Down
72 changes: 70 additions & 2 deletions qutip/core/qobj/_state.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ._base import Qobj, _QobjBuilder
from .. import data as _data

from typing import Any, Literal

__all__ = []

Expand All @@ -25,6 +25,75 @@ def proj(self) -> Qobj:
isherm=True,
copy=False)

def norm(
self,
norm: Literal["l2", "max"] = "l2",
kwargs: dict[str, Any] = None
) -> float:
"""
Norm of a quantum object.

Default norm is L2-norm. Other
ket and operator norms may be specified using the `norm` parameter.

Parameters
----------
norm : str, default: "l2"
Which type of norm to use. Allowed values are 'l2' and 'max'.

kwargs : dict, optional
Additional keyword arguments to pass on to the relevant norm
solver. See details for each norm function in :mod:`.data.norm`.

Returns
-------
norm : float
The requested norm of the operator or state quantum object.
"""
norm = norm or "l2"
if norm not in ["l2", "max"]:
raise ValueError(
"vector norm must be in {'k2', 'max'}"
)

kwargs = kwargs or {}
return {
'l2': _data.norm.l2,
'max': _data.norm.max
}[norm](self._data, **kwargs)

def unit(
self,
inplace: bool = False,
norm: Literal["l2", "max"] = "l2",
kwargs: dict[str, Any] = None
) -> Qobj:
"""
Operator or state normalized to unity. Uses norm from Qobj.norm().

Parameters
----------
inplace : bool, default: False
Do an in-place normalization
norm : str, default: "l2"
Requested norm for states / operators.
kwargs : dict, optional
Additional key-word arguments to be passed on to the relevant norm
function (see :meth:`.norm` for more details).

Returns
-------
obj : :class:`.Qobj`
Normalized quantum object. Will be the `self` object if in place.
"""
norm_ = self.norm(norm=norm, kwargs=kwargs)
if inplace:
self.data = _data.mul(self.data, 1 / norm_)
out = self
else:
out = self / norm_
return out


class Bra(_StateQobj):
def __init__(self, data, dims, **flags):
Expand All @@ -39,7 +108,6 @@ def isbra(self) -> bool:
return True



class Ket(_StateQobj):
def __init__(self, data, dims, **flags):
super().__init__(data, dims, **flags)
Expand Down
Loading