States#
In Qhronology, quantum states are both represented and constructed natively in the computational basis (also known as the standard or \(z\)-basis). This is achieved primarily through the use of the QuantumState
class,
from qhronology.quantum.states import QuantumState
which itself relies chiefly on functionality provided by the matrix-generating quantum_state()
function:
from qhronology.mechanics.matrices import quantum_state
Characterization of quantum states is facilitated by two properties: form
distinguishes between states which are "vector"
or "matrix"
, while kind
distinguishes those which are "pure"
or "mixed"
. Of the four combinations (pairs) of these properties, all are valid except for the pairing of "vector"
and "mixed"
. Therefore, to expedite and simplify state instantiation, the following subclasses of the base class QuantumState
are provided:
from qhronology.quantum.states import VectorState, MatrixState, PureState, MixedState
These classes are specialized (or restrictive) subclasses, meaning that they do not extend the base class in any way, and instead merely constrain its functionality in order to enforce the desired behaviour. They therefore allow for quantum state objects to be initialized in ways that are more concise than the general QuantumState
class.
Main class#
- class QuantumState(
- spec: MutableDenseMatrix | ndarray | list[list[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str]] | list[tuple[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str, int | list[int]]],
- form: str | None = None,
- kind: str | None = None,
- dim: int | None = None,
- symbols: dict[MatrixSymbol | MatrixElement | Symbol | str, dict[str, Any]] | None = None,
- conditions: list[tuple[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str, Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str]] | None = None,
- conjugate: bool | None = None,
- norm: bool | Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str | None = None,
- label: str | None = None,
- notation: str | None = None,
- family: str | None = None,
- debug: bool | None = None,
Bases:
QuantitiesMixin
,OperationsMixin
,QuantumObject
A class for creating quantum states and storing their metadata.
Instances provide complete descriptions of both vector and matrix quantum states, along with various associated attributes (such as mathematical conditions, including normalization). The internal state of the class is expressly mutable, and a selection of useful methods are provided with which the state can be manipulated and otherwise transformed in various quantum-mechanically significant ways. This includes:
normalization
(partial) trace
measurement
postselection
- Parameters:
spec –
The specification of the quantum state. Provides a complete description of the state’s values in a standard
dim
-dimensional basis. Can be one of:a SymPy matrix (
mat
)a NumPy array (
arr
)a list of lists of numerical, symbolic, or string expressions (that collectively specify a matrix) (
list[list[num | sym | str]]
)a list of 2-tuples of numerical, symbolic, or string coefficients and their respective number-basis specifications (
list[tuple[num | sym | str, int | list[int]]]
)
form (str) – A string specifying the form for the quantum state to take. Can be either of
"vector"
or"matrix"
. Defaults to"matrix"
.kind (str) – A string specifying the kind for the quantum state to take. Can be either of
"mixed"
or"pure"
. Defaults to"mixed"
.dim (int) – The dimensionality of the quantum state’s Hilbert space. Must be a non-negative integer. Defaults to
2
.symbols (dict[sym | str, dict[str, Any]]) – A dictionary in which the keys are individual symbols (usually found within the state specification
spec
) and the values are dictionaries of their respective SymPy keyword-argumentassumptions
. Defaults to{}
.conditions (list[tuple[num | sym | str, num | sym | str]]) – A list of \(2\)-tuples of conditions to be applied to the state. All instances of the expression in each tuple’s first element are replaced by the expression in the respective second element. This uses the same format as the SymPy
subs()
method. The order in which they are applied is simply their order in the list. Defaults to[]
.conjugate (bool) – Whether to perform Hermitian conjugation on the state when it is called. Defaults to
False
.norm (bool | num | sym | str) – The value to which the state is normalized. If
True
, normalizes to a value of \(1\). IfFalse
, does not normalize. Defaults toFalse
.label (str) – The unformatted string used to represent the state in mathematical expressions. Must have a non-zero length. Defaults to
"ρ"
(ifform == "matrix"
) or"ψ"
(ifform == "vector"
).notation (str) – The formatted string used to represent the state in mathematical expressions. When not
None
, overrides the value passed tolabel
. Must have a non-zero length. Not intended to be set by the user in most cases. Defaults toNone
.family (str) – A string expressing the kind of block element for which the object is to be visualized. Not intended to be set by the user. Defaults to
"LSTICK"
.debug (bool) – Whether to print the internal state (held in
matrix
) on change. Defaults toFalse
.
Examples
>>> qubit_vector = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", "1")], ... norm=1, ... label="ψ", ... ) >>> qubit_vector.output() Matrix([ [a], [b]]) >>> qubit_vector.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> qubit_vector.diagram()
>>> qutrit_vector = QuantumState( ... spec=[("a", [0]), ("b", [1]), ("c", [2])], ... form="vector", ... dim=3, ... symbols={ ... "a": {"complex": True}, ... "b": {"complex": True}, ... "c": {"complex": True}, ... }, ... conditions=[("a*conjugate(a) + b*conjugate(b) + c*conjugate(c)", "1")], ... norm=1, ... label="φ", ... ) >>> qutrit_vector.output() Matrix([ [a], [b], [c]]) >>> qutrit_vector.print() |φ⟩ = a|0⟩ + b|1⟩ + c|2⟩ >>> qutrit_vector.diagram()
>>> qubit_pure = QuantumState( ... spec=[("α", [0]), ("β", [1])], ... form="matrix", ... kind="pure", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("α*conjugate(α) + β*conjugate(β)", 1)], ... norm=1, ... label="ξ", ... ) >>> qubit_pure.output() Matrix([ [α*conjugate(α), α*conjugate(β)], [β*conjugate(α), β*conjugate(β)]]) >>> qubit_pure.print() |ξ⟩⟨ξ| = α*conjugate(α)|0⟩⟨0| + α*conjugate(β)|0⟩⟨1| + β*conjugate(α)|1⟩⟨0| + β*conjugate(β)|1⟩⟨1| >>> qubit_pure.diagram()
>>> qubit_mixed = QuantumState( ... spec=[("p", [0]), ("1 - p", [1])], ... form="matrix", ... kind="mixed", ... symbols={"p": {"real": True}}, ... norm=1, ... label="τ", ... ) >>> qubit_mixed.output() Matrix([ [p, 0], [0, 1 - p]]) >>> qubit_mixed.print() τ = p|0⟩⟨0| + (1 - p)|1⟩⟨1| >>> qubit_mixed.diagram()
>>> custom_vector = QuantumState(spec=[["μ"], ["ν"]], kind="mixed", label="η") >>> custom_vector.output() Matrix([ [μ*conjugate(μ), μ*conjugate(ν)], [ν*conjugate(μ), ν*conjugate(ν)]]) >>> custom_vector.print() η = μ*conjugate(μ)|0⟩⟨0| + μ*conjugate(ν)|0⟩⟨1| + ν*conjugate(μ)|1⟩⟨0| + ν*conjugate(ν)|1⟩⟨1| >>> custom_vector.diagram()
>>> custom_matrix = QuantumState(spec=[["w", "x"], ["y", "z"]], kind="mixed", label="ω") >>> custom_matrix.output() Matrix([ [w, x], [y, z]]) >>> custom_matrix.print() ω = w|0⟩⟨0| + x|0⟩⟨1| + y|1⟩⟨0| + z|1⟩⟨1| >>> custom_matrix.diagram()
>>> bell_state = QuantumState(spec=[(1, [0, 0]), (1, [1, 1])], form="vector", norm=1, label="Φ") >>> bell_state.output() Matrix([ [sqrt(2)/2], [ 0], [ 0], [sqrt(2)/2]]) >>> bell_state.print() |Φ⟩ = sqrt(2)/2|0,0⟩ + sqrt(2)/2|1,1⟩ >>> bell_state.diagram()
>>> tripartite_zero = QuantumState(spec=[(1, [0, 0, 0])], form="vector", label="0,0,0") >>> tripartite_zero.output() Matrix([ [1], [0], [0], [0], [0], [0], [0], [0]]) >>> tripartite_zero.print() |0,0,0⟩ = |0,0,0⟩ >>> tripartite_zero.diagram()
Constructor argument properties#
- property QuantumState.spec: MutableDenseMatrix | ndarray | list[list[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str]] | list[tuple[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str, int | list[int]]]#
The matrix representation of the quantum state. Provides a complete description of the state in a standard
dim
-dimensional basis.
- property QuantumState.form: str#
The form of the object. Can be either of
"vector"
or"matrix"
. OnlyQuantumState
objects can be"vector"
.
- property QuantumState.kind: str#
The kind of quantum state. Can be either of
"mixed"
or"pure"
.
- property QuantumState.dim: int#
The dimensionality of the quantum object. Must be a non-negative integer.
- property QuantumState.symbols: dict[MatrixSymbol | MatrixElement | Symbol | str, dict[str, Any]]#
A dictionary in which the keys are individual symbols (contained within the object’s matrix representation) and the values are dictionaries of their respective SymPy keyword-argument
assumptions
(“predicates”). A full list of currently supported predicates, and their defaults, is as follows:"algebraic"
:True
"commutative"
:True
"complex"
:True
"extended_negative"
:False
"extended_nonnegative"
:True
"extended_nonpositive"
:False
"extended_nonzero"
:True
"extended_positive"
:True
"extended_real"
:True
"finite"
:True
"hermitian"
:True
"imaginary"
:False
"infinite"
:False
"integer"
:True
"irrational"
:False
"negative"
:False
"noninteger"
:False
"nonnegative"
:True
"nonpositive"
:False
"nonzero"
:True
"positive"
:True
"rational"
:True
"real"
:True
"transcendental"
:False
"zero"
:False
- property QuantumState.conditions: list[tuple[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str, Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str]]#
A list of \(2\)-tuples of conditions to be applied to the object’s matrix representation.
- property QuantumState.norm: bool | Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str#
The value to which the state is normalized. If
True
, normalizes to a value of \(1\). IfFalse
, does not normalize.Examples of valid values include:
1/2
"1/d"
"a*conjugate(a) + b*conjugate(b)"
- property QuantumState.conjugate: bool#
Whether to perform Hermitian conjugation on the object when it is called.
- property QuantumState.label: str#
The unformatted string used to represent the object in mathematical expressions. Must have a non-zero length.
- property QuantumState.notation: str#
The formatted string used to represent the object in mathematical expressions. When set, overrides the value of the
label
property. Must have a non-zero length. Not intended to be set by the user in most cases.
- property QuantumState.family: str#
The code of the block element that the object is to be visualized as. Not intended to be set by the user.
- property QuantumState.debug: bool#
Whether to print the object’s matrix representation (stored in the
matrix
property) on mutation.
Read-only properties#
- property QuantumState.systems: list[int]#
Read-only property containing an ordered list of the numerical indices of the object’s systems.
- property QuantumState.num_systems: int#
Read-only property containing the number of systems which the state spans. The current value is calculated from the state’s matrix representation and its dimensionality
dim
.
- property QuantumState.is_vector: bool#
Test for whether the object is a vector. Returns
True
if so, otherwiseFalse
.
- property QuantumState.matrix: MutableDenseMatrix#
The matrix representation of the object.
Considered read-only (this is strictly enforced by
QuantumGate
class and its derivatives), though can be (indirectly) mutated by some derived classes (such asQuantumState
). Not intended to be set directly by the user.
Methods#
- QuantumState.output(
- conditions: list[tuple[Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str, Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str]] | None = None,
- simplify: bool | None = None,
- conjugate: bool | None = None,
- norm: bool | Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str | None = None,
Construct the state’s matrix representation, perform any necessary transformations on it, and return it.
- Parameters:
conditions (list[tuple[num | sym | str, num | sym | str]]) – Algebraic conditions to be applied to the state. Defaults to the value of
self.conditions
.simplify (bool) – Whether to perform algebraic simplification on the state. Defaults to
False
.conjugate (bool) – Whether to perform Hermitian conjugation on the state. If
False
, does not conjugate. Defaults to the value ofself.conjugate
.norm (bool | num | sym | str) – The value to which the state is normalized. If
False
, does not normalize. Defaults to the value ofself.norm
.
- Returns:
mat – The matrix or vector representation of the quantum state.
- QuantumState.print(
- delimiter: str | None = None,
- product: bool | None = None,
- return_string: bool | None = None,
Print or return a mathematical expression of the quantum object as a string.
- Parameters:
delimiter (str) – A string containing the character(s) with which to delimit (i.e., separate) the values in the ket and/or bra terms in the mathematical expression. Defaults to
","
.product (bool) – Whether to represent the mathematical expression using tensor products. Only applies if the object is a multipartite composition. Defaults to
False
.return_string (bool) – Whether to return the mathematical expression as a string. Defaults to
False
.
- Returns:
None – Returned only if
return_string
isFalse
.str – The constructed mathematical expression. Returned only if
return_string
isTrue
.
Examples
>>> vector_state = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> vector_state.output() Matrix([ [a], [b]]) >>> vector_state.print() |ψ⟩ = a|0⟩ + b|1⟩
>>> mixed_matrix_state = QuantumState( ... spec=[("a", [0]), ("b", [1])], form="matrix", label="ρ" ... ) >>> mixed_matrix_state.output() Matrix([ [a, 0], [0, b]]) >>> mixed_matrix_state.print() ρ = a|0⟩⟨0| + b|1⟩⟨1|
>>> pure_matrix_state = QuantumState( ... spec=[("a", [0]), ("b", [1])], form="matrix", kind="pure", label="ψ" ... ) >>> pure_matrix_state.output() Matrix([ [a*conjugate(a), a*conjugate(b)], [b*conjugate(a), b*conjugate(b)]]) >>> pure_matrix_state.print() |ψ⟩⟨ψ| = a*conjugate(a)|0⟩⟨0| + a*conjugate(b)|0⟩⟨1| + b*conjugate(a)|1⟩⟨0| + b*conjugate(b)|1⟩⟨1|
>>> composite_vector_state = QuantumState( ... spec=[("a", [0, 0]), ("b", [1, 1])], form="vector", label="ψ" ... ) >>> composite_vector_state.output() Matrix([ [a], [0], [0], [b]]) >>> composite_vector_state.print() |ψ⟩ = a|0,0⟩ + b|1,1⟩ >>> composite_vector_state.print(delimiter="") |ψ⟩ = a|00⟩ + b|11⟩ >>> composite_vector_state.print(product=True) |ψ⟩ = a|0⟩⊗|0⟩ + b|1⟩⊗|1⟩
>>> composite_mixed_matrix_state = QuantumState( ... spec=[("a", [0, 0]), ("b", [1, 1])], form="matrix", label="ρ" ... ) >>> composite_mixed_matrix_state.output() Matrix([ [a, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, b]]) >>> composite_mixed_matrix_state.print() ρ = a|0,0⟩⟨0,0| + b|1,1⟩⟨1,1| >>> composite_mixed_matrix_state.print(delimiter="") ρ = a|00⟩⟨00| + b|11⟩⟨11| >>> composite_mixed_matrix_state.print(product=True) ρ = a|0⟩⟨0|⊗|0⟩⟨0| + b|1⟩⟨1|⊗|1⟩⟨1|
>>> composite_pure_matrix_state = QuantumState( ... spec=[("a", [0, 0]), ("b", [1, 1])], form="matrix", kind="pure", label="ψ" ... ) >>> composite_pure_matrix_state.output() Matrix([ [a*conjugate(a), 0, 0, a*conjugate(b)], [ 0, 0, 0, 0], [ 0, 0, 0, 0], [b*conjugate(a), 0, 0, b*conjugate(b)]]) >>> composite_pure_matrix_state.print() |ψ⟩⟨ψ| = a*conjugate(a)|0,0⟩⟨0,0| + a*conjugate(b)|0,0⟩⟨1,1| + b*conjugate(a)|1,1⟩⟨0,0| + b*conjugate(b)|1,1⟩⟨1,1| >>> composite_pure_matrix_state.print(delimiter="") |ψ⟩⟨ψ| = a*conjugate(a)|00⟩⟨00| + a*conjugate(b)|00⟩⟨11| + b*conjugate(a)|11⟩⟨00| + b*conjugate(b)|11⟩⟨11| >>> composite_pure_matrix_state.print(product=True) |ψ⟩⟨ψ| = a*conjugate(a)|0⟩⟨0|⊗|0⟩⟨0| + a*conjugate(b)|0⟩⟨1|⊗|0⟩⟨1| + b*conjugate(a)|1⟩⟨0|⊗|1⟩⟨0| + b*conjugate(b)|1⟩⟨1|⊗|1⟩⟨1|
- QuantumState.diagram(
- pad: tuple[int, int] | None = None,
- sep: tuple[int, int] | None = None,
- style: str | None = None,
- return_string: bool | None = None,
Print or return a circuit diagram of the quantum object as a multiline string.
- Parameters:
pad (tuple[int, int]) – A two-tuple describing the horizontal and vertical interior paddings between the content at the centre of the object (e.g., its label) and its outer edge (e.g., block border). Both integers must be non-negative. Defaults to
(0, 0)
.sep (tuple[int, int]) – A two-tuple describing the horizontal and vertical exterior separation distances at the object’s edges. Both integers must be non-negative. Defaults to
(1, 1)
.style (str) – A string specifying the style for the circuit visualization to take. Can be any of
"ascii"
,"unicode"
, or"unicode_alt"
. Defaults to"unicode"
.return_string (bool) – Whether to return the assembled diagram as a multiline string. Defaults to
False
.
- Returns:
None – Returned only if
return_string
isFalse
.str – The rendered circuit diagram. Returned only if
return_string
isTrue
.
Note
The quality of the visualization depends greatly on the output’s configuration. For best results, the terminal should have a monospace font with good Unicode coverage.
Examples
For usage examples, please see those of the
QuantumState
class itself.
Operations#
All of these methods (except for reset()
) are inherited from OperationsMixin
.
- QuantumState.reset()[source]#
Reset the quantum state’s internal matrix state (specifically its
matrix
property) to its original value at instantiation.Note
This reset only the
matrix
property of the instance. All other attributes and properties are unchanged.
- QuantumState.densify()#
Convert the state to its equivalent (density) matrix representation.
States that are already in density matrix form are unmodified.
Examples
>>> psi = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> psi.densify() >>> psi.print() |ψ⟩⟨ψ| = a*conjugate(a)|0⟩⟨0| + a*conjugate(b)|0⟩⟨1| + b*conjugate(a)|1⟩⟨0| + b*conjugate(b)|1⟩⟨1|
- QuantumState.dagger()#
Perform conjugate transposition on the state.
Examples
>>> psi = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> psi.dagger() >>> psi.print() ⟨ψ| = conjugate(a)⟨0| + conjugate(b)⟨1|
- QuantumState.simplify(
- comprehensive: bool | None = None,
Apply a forced simplification to the state using the values of its
symbols
andconditions
properties.Useful if intermediate simplification is required during a sequence of mutating operations in order to process the state into a more desirable form.
- Parameters:
comprehensive (bool) – Whether the simplifying algorithm should use a relatively efficient subset of simplifying operations (
False
), or alternatively use a larger, more powerful (but slower) set (True
). Defaults toFalse
.
Note
If
comprehensive
isTrue
, the simplification algorithm will likely take far longer to execute than ifcomprehensive
wereFalse
.Examples
>>> matrix = sp.Matrix( ... [ ... ["(a**2 - 1)/(a - 1) - 1", "log(cos(b) + I*sin(b))/I"], ... ["acos((exp(I*c) + exp(-I*c))/2)", "d**log(E*(sin(d)**2 + cos(d)**2))"], ... ] ... ) >>> rho = QuantumState(spec=matrix, form="matrix", label="ρ") >>> rho.print() ρ = (-1 + (a**2 - 1)/(a - 1))|0⟩⟨0| + -I*log(I*sin(b) + cos(b))|0⟩⟨1| + acos(exp(I*c)/2 + exp(-I*c)/2)|1⟩⟨0| + d**log(E*(sin(d)**2 + cos(d)**2))|1⟩⟨1| >>> rho.simplify() >>> rho.print() ρ = a|0⟩⟨0| + b|0⟩⟨1| + c|1⟩⟨0| + d|1⟩⟨1|
- QuantumState.apply(
- function: Callable,
- arguments: dict[str, Any] | None = None,
Apply a Python function (
function
) to the state.Useful when used with SymPy’s symbolic-manipulation functions, such as:
simplify()
expand()
factor()
collect()
cancel()
apart()
More can be found at:
- Parameters:
function (Callable) – A Python function. Its first non-keyword argument must be able to take a mathematical expression or a matrix/array of such types.
arguments (dict[str, str]) – A dictionary of keyword arguments (both keys and values as strings) to pass to the
function
call. Defaults to{}
.
Examples
>>> psi = QuantumState( ... spec=[("a*b + b*c + c*a", [0]), ("x*y + y*z + z*x", [1])], form="vector", label="ψ" ... ) >>> psi.print() |ψ⟩ = (a*b + a*c + b*c)|0⟩ + (x*y + x*z + y*z)|1⟩ >>> psi.apply(sp.collect, {"syms": ["a", "x"]}) >>> psi.print() |ψ⟩ = (a*(b + c) + b*c)|0⟩ + (x*(y + z) + y*z)|1⟩ >>> psi.apply(sp.expand) >>> psi.print() |ψ⟩ = (a*b + a*c + b*c)|0⟩ + (x*y + x*z + y*z)|1⟩
- QuantumState.rewrite(
- function: Callable,
Rewrite the elements of the state using the given mathematical function (
function
).Useful when used with SymPy’s mathematical functions, such as:
exp()
log()
sin()
cos()
- Parameters:
function (Callable) – A SymPy mathematical function.
Examples
>>> psi = QuantumState(spec=[("cos(θ)", [0]), ("sin(θ)", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = cos(θ)|0⟩ + sin(θ)|1⟩ >>> psi.rewrite(sp.exp) >>> psi.print() |ψ⟩ = (exp(I*θ)/2 + exp(-I*θ)/2)|0⟩ + -I*(exp(I*θ) - exp(-I*θ))/2|1⟩
- QuantumState.normalize(
- norm: Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str | None = None,
Perform a forced (re)normalization on the state to the value specified (
norm
).Useful when applied to the current quantum state both before and after mutating operations, prior to any simplification (such as renormalization) performed on the processed output (obtained via the
state()
method).- Parameters:
norm (num | sym | str) – The value to which the state is normalized. Defaults to
1
.
Examples
>>> identity = QuantumState(spec=[("1", [0]), ("1", [1])], label="I") >>> identity.print() I = |0⟩⟨0| + |1⟩⟨1| >>> identity.normalize() >>> identity.print() I = 1/2|0⟩⟨0| + 1/2|1⟩⟨1|
>>> psi = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> psi.normalize() >>> psi.print() |ψ⟩ = a/sqrt(a*conjugate(a) + b*conjugate(b))|0⟩ + b/sqrt(a*conjugate(a) + b*conjugate(b))|1⟩
- QuantumState.coefficient(
- scalar: Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol | str | None = None,
Multiply the state by a scalar value (
scalar
).Can be useful to manually (re)normalize states, or introduce a phase factor.
- Parameters:
scalar (num | sym | str) – The value by which the state is multiplied. Defaults to
1
.
Examples
>>> psi = QuantumState(spec=[("1", [0]), ("1", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = |0⟩ + |1⟩ >>> psi.coefficient(1 / sp.sqrt(2)) >>> psi.print() |ψ⟩ = sqrt(2)/2|0⟩ + sqrt(2)/2|1⟩
- QuantumState.partial_trace(
- targets: int | list[int] | None = None,
- discard: bool | None = None,
- optimize: bool | None = None,
Perform a partial trace operation on the state.
Performs a total trace if
targets
is unspecified.- Parameters:
targets (int | list[int]) – The numerical index/indices of the subsystem(s) to be partially traced over. Indexing begins at
0
. Defaults to[]
.discard (bool) – Whether the systems corresponding to the indices given in
targets
are to be discarded (True
) or kept (False
). Defaults toTrue
.optimize (bool) – Whether to optimize the partial trace implementation’s algorithm. Can greatly increase the computational efficiency at the cost of a larger memory footprint during computation. Defaults to
True
.
Examples
>>> psi = QuantumState( ... spec=[("a*u", [0, 0]), ("b*u", [1, 0]), ("a*v", [0, 1]), ("b*v", [1, 1])], ... form="vector", ... conditions=[ ... ("a*conjugate(a) + b*conjugate(b)", "1"), ... ("u*conjugate(u) + v*conjugate(v)", "1"), ... ], ... label="Ψ", ... ) >>> psi.print() |Ψ⟩ = a*u|0,0⟩ + a*v|0,1⟩ + b*u|1,0⟩ + b*v|1,1⟩ >>> psi.partial_trace([1]) >>> psi.simplify() >>> psi.notation = "ρ" >>> psi.print() ρ = a*conjugate(a)|0⟩⟨0| + a*conjugate(b)|0⟩⟨1| + b*conjugate(a)|1⟩⟨0| + b*conjugate(b)|1⟩⟨1|
>>> bell = QuantumState( ... spec=[("1", [0, 0]), ("1", [1, 1])], form="vector", norm=1, label="Φ" ... ) >>> bell.print() |Φ⟩ = sqrt(2)/2|0,0⟩ + sqrt(2)/2|1,1⟩ >>> bell.partial_trace([0]) >>> bell.notation = "ρ" >>> bell.print() ρ = 1/2|0⟩⟨0| + 1/2|1⟩⟨1|
- QuantumState.measure(
- operators: list[mat | arr | QuantumObject],
- targets: int | list[int] | None = None,
- observable: bool | None = None,
- statistics: bool | None = None,
Perform a quantum measurement on one or more systems (indicated in
targets
) of the state.This method has two main modes of operation:
When
statistics
isTrue
, the (reduced) state (\(\op{\rho}\)) (residing on the systems indicated intargets
) is measured and the set of resulting statistics is returned. This takes the form of an ordered list of values \(\{p_i\}_i\) associated with each given operator, where:\(p_i = \trace[\Kraus_i^\dagger \Kraus_i \op{\rho}]\) (measurement probabilities) when
observable
isFalse
(operators
is a list of Kraus operators or projectors \(\Kraus_i\))\(p_i = \trace[\Observable_i \op{\rho}]\) (expectation values) when
observable
isTrue
(operators
is a list of observables \(\Observable_i\))
When
statistics
isFalse
, the (reduced) state (\(\op{\rho}\)) (residing on the systems indicated intargets
) is measured and mutated it according to its predicted post-measurement form (i.e., the sum of all possible measurement outcomes). This yields the transformed states:When
observable
isFalse
:
(275)#\[\op{\rho}^\prime = \sum_i \Kraus_i \op{\rho} \Kraus_i^\dagger.\]When
observable
isTrue
:
(276)#\[\op{\rho}^\prime = \sum_i \trace[\Observable_i \op{\rho}]\Observable_i.\]
In the case where
operators
contains only a single item (\(\Kraus\)) and the current state (\(\ket{\psi}\)) is a vector form, the transformation of the state is in accordance with the rule(277)#\[\ket{\psi^\prime} = \frac{\Kraus \ket{\psi}} {\sqrt{\bra{\psi} \Kraus^\dagger \Kraus \ket{\psi}}}\]when
observable
isFalse
. In all other mutation cases, the post-measurement state is a matrix, even if the pre-measurement state was a vector.The items in the list
operators
can also be vectors (e.g., \(\ket{\xi_i}\)), in which case each is converted into its corresponding operator matrix representation (e.g., \(\ket{\xi_i}\bra{\xi_i}\)) prior to any measurements.- Parameters:
operators (list[mat | arr | QuantumObject]) – The operator(s) with which to perform the measurement. These would typically be a (complete) set of Kraus operators forming a POVM, a (complete) set of (orthogonal) projectors forming a PVM, or a set of observables constituting a complete basis for the relevant state space.
targets (int | list[int]) – The numerical indices of the subsystem(s) to be measured. They must be consecutive, and their number must match the number of systems spanned by all given operators. Indexing begins at
0
. All other systems are discarded (traced over) in the course of performing the measurement. Defaults to the value ofself.systems
.observable (bool) – Whether to treat the items in
operators
as observables instead of Kraus operators or projectors. Defaults toFalse
.statistics (bool) – Whether to return a list of probabilities (
True
) or mutate the state into a post-measurement probabilistic sum of all outcomes (False
). Defaults toFalse
.
- Returns:
None – Returned only if
statistics
isFalse
.num | sym | list[num | sym] – A list of probabilities corresponding to each operator given in
operators
. Returned only ifstatistics
isTrue
.
Note
This method does not check for validity of supplied POVMs or the completeness of sets of observables, nor does it renormalize the post-measurement state.
Examples
>>> psi = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> I = Pauli(index=0) >>> X = Pauli(index=1) >>> Y = Pauli(index=2) >>> Z = Pauli(index=3) >>> psi.measure(operators=[I, X, Y, Z], observable=True, statistics=True) [a*conjugate(a) + b*conjugate(b), a*conjugate(b) + b*conjugate(a), I*(a*conjugate(b) - b*conjugate(a)), a*conjugate(a) - b*conjugate(b)] >>> psi.measure(operators=[I, X, Y, Z], observable=True, statistics=False) >>> psi.simplify() >>> psi.coefficient(sp.Rational(1, 2)) >>> psi.print() |ψ⟩⟨ψ| = a*conjugate(a)|0⟩⟨0| + a*conjugate(b)|0⟩⟨1| + b*conjugate(a)|1⟩⟨0| + b*conjugate(b)|1⟩⟨1|
>>> from qhronology.mechanics.matrices import ket >>> psi = QuantumState(spec=[("a", [0]), ("b", [1])], form="vector", label="ψ") >>> psi.print() |ψ⟩ = a|0⟩ + b|1⟩ >>> psi.measure(operators=[ket(0), ket(1)], observable=False, statistics=True) [a*conjugate(a), b*conjugate(b)] >>> psi.measure(operators=[ket(0), ket(1)], observable=False, statistics=False) >>> psi.notation = "ρ" >>> psi.print() ρ = a*conjugate(a)|0⟩⟨0| + b*conjugate(b)|1⟩⟨1|
- QuantumState.postselect(
- postselections: list[tuple[mat | arr | QuantumObject, int]],
Perform postselection on the state against the operators(s) specified in
postselections
.The postselections can be given in either vector or matrix form. For the former, the transformation of the vector state \(\ket{\Psi}\) follows the standard rule
(278)#\[\ket{\Psi^\prime} = \braket{\phi}{\Psi}\]where \(\ket{\phi}\) is the postselection vector. In the case of a matrix form \(\op{\omega}\), the notion of postselection of a density matrix state \(\op{\rho}\) naturally generalizes to
(279)#\[\op{\rho}^\prime = \trace_{\{i\}}[\op{\omega} \op{\rho}]\]where \(\{i\}\) is the set of indices corresponding to the subsystem(s) upon which the postselection is performed.
If multiple postselections are supplied, the state will be successively postselected in the order in which they are given. If a vector state is postselected against a matrix form, it will automatically be transformed into its matrix form as necessary.
- Parameters:
postselections (list[tuple[mat | arr | QuantumObject, int]]) – A list of 2-tuples of vectors or matrix operators paired with the first (smallest) index of their postselection target systems.
Note
Any classes given in
postselections
that are derived from theQuantumObject
base class (such asQuantumState
andQuantumGate
) will have theirsymbols
andconditions
properties merged into the currentQuantumState
instance.Examples
>>> psi = QuantumState(spec=[("a", [0, 0]), ("b", [1, 1])], form="vector", label="Ψ") >>> phi = QuantumState(spec=[("c", [0]), ("d", [1])], form="vector", label="φ") >>> psi.print() |Ψ⟩ = a|0,0⟩ + b|1,1⟩ >>> phi.print() |φ⟩ = c|0⟩ + d|1⟩ >>> psi.postselect([(phi, [0])]) >>> psi.label = "Ψ'" >>> psi.print() |Ψ'⟩ = a*conjugate(c)|0⟩ + b*conjugate(d)|1⟩
>>> from qhronology.mechanics.matrices import ket >>> psi = QuantumState(spec=[("a", [0, 0]), ("b", [1, 1])], form="vector", label="Ψ") >>> psi.print() |Ψ⟩ = a|0,0⟩ + b|1,1⟩ >>> psi.label = "Ψ'" >>> psi.postselect([(ket(0), [0])]) >>> psi.print() |Ψ'⟩ = a|0⟩ >>> psi.reset() >>> psi.postselect([(ket(1), [0])]) >>> psi.print() |Ψ'⟩ = b|1⟩
Quantities#
All of these methods are inherited from QuantitiesMixin
.
- QuantumState.trace() Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol #
Calculate the (complete) trace \(\trace[\op{\rho}]\) of the internal state (\(\op{\rho}\)).
- Returns:
num | sym – The trace of the internal state.
Examples
>>> state = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state.trace() 1
>>> state = QuantumState( ... spec=[(1, [0]), (1, [1])], ... kind="mixed", ... symbols={"d": {"real": True}}, ... norm="1/d", ... ) >>> state.trace() 1/d
- QuantumState.purity() Number | generic | Basic | MatrixSymbol | MatrixElement | Symbol #
Calculate the purity (\(\Purity\)) of the internal state (\(\op{\rho}\)):
(280)#\[\Purity(\op{\rho}) = \trace[\op{\rho}^2].\]- Returns:
num | sym – The purity of the internal state.
Examples
>>> state = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state.purity() 1
>>> state = QuantumState(spec=[("p", [0]), ("1 - p", [1])], kind="mixed", norm=1) >>> state.purity() p**2 + (1 - p)**2
- QuantumState.distance(
- state: mat | QuantumObject,
Calculate the trace distance (\(\TraceDistance\)) between the internal state (\(\op{\rho}\)) and the given
state
(\(\op{\tau}\)):(281)#\[\TraceDistance(\op{\rho}, \op{\tau}) = \frac{1}{2}\trace{\abs{\op{\rho} - \op{\tau}}}.\]- Parameters:
state (mat | QuantumObject) – The given state.
- Returns:
num | sym – The trace distance between the internal state and
state
.
Examples
>>> state_A = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("c", [0]), ("d", [1])], ... form="vector", ... symbols={"c": {"complex": True}, "d": {"complex": True}}, ... conditions=[("c*conjugate(c) + d*conjugate(d)", 1)], ... norm=1, ... ) >>> state_A.distance(state_A) 0 >>> state_B.distance(state_B) 0 >>> state_A.distance(state_B) sqrt((a*conjugate(b) - c*conjugate(d))*(b*conjugate(a) - d*conjugate(c)) + (b*conjugate(b) - d*conjugate(d))**2)/2 + sqrt((a*conjugate(a) - c*conjugate(c))**2 + (a*conjugate(b) - c*conjugate(d))*(b*conjugate(a) - d*conjugate(c)))/2
>>> state_A = QuantumState( ... spec=[("p", [0]), ("1 - p", [1])], ... kind="mixed", ... symbols={"p": {"positive": True}}, ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("q", [0]), ("1 - q", [1])], ... kind="mixed", ... symbols={"q": {"positive": True}}, ... norm=1, ... ) >>> state_A.distance(state_B) Abs(p - q)
>>> plus_state = QuantumState(spec=[(1, [0]), (1, [1])], form="vector", norm=1) >>> minus_state = QuantumState(spec=[(1, [0]), (-1, [1])], form="vector", norm=1) >>> plus_state.distance(minus_state) 1
- QuantumState.fidelity(
- state: mat | QuantumObject,
Calculate the fidelity (\(\Fidelity\)) between the internal state (\(\op{\rho}\)) and the given
state
(\(\op{\tau}\)):(282)#\[\Fidelity(\op{\rho}, \op{\tau}) = \left(\trace{\sqrt{\sqrt{\op{\rho}}\,\op{\tau}\sqrt{\op{\rho}}}}\right)^2.\]- Parameters:
state (mat | QuantumObject) – The given state.
- Returns:
num | sym – The fidelity between the internal state and
state
.
Examples
>>> state_A = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("c", [0]), ("d", [1])], ... form="vector", ... symbols={"c": {"complex": True}, "d": {"complex": True}}, ... conditions=[("c*conjugate(c) + d*conjugate(d)", 1)], ... norm=1, ... ) >>> state_A.fidelity(state_A) 1 >>> state_B.fidelity(state_B) 1 >>> state_A.fidelity(state_B) (a*conjugate(c) + b*conjugate(d))*(c*conjugate(a) + d*conjugate(b))
>>> state_A = QuantumState( ... spec=[("p", [0]), ("1 - p", [1])], ... kind="mixed", ... symbols={"p": {"positive": True}}, ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("q", [0]), ("1 - q", [1])], ... kind="mixed", ... symbols={"q": {"positive": True}}, ... norm=1, ... ) >>> state_A.fidelity(state_B) (sqrt(p)*sqrt(q) + sqrt((1 - p)*(1 - q)))**2
>>> plus_state = QuantumState(spec=[(1, [0]), (1, [1])], form="vector", norm=1) >>> minus_state = QuantumState(spec=[(1, [0]), (-1, [1])], form="vector", norm=1) >>> plus_state.fidelity(minus_state) 0
- QuantumState.entropy(
- state: mat | QuantumObject = None,
- base: num | None = None,
Calculate the relative von Neumann entropy (\(\Entropy\)) between the internal state (\(\op{\rho}\)) and the given
state
(\(\op{\tau}\)):(283)#\[\Entropy(\op{\rho} \Vert \op{\tau}) = \trace\bigl[\op{\rho} (\log_\Base\op{\rho} - \log_\Base\op{\tau})\bigr].\]If
state
is not specified (i.e.,None
), calculate the ordinary von Neumann entropy of the internal state (\(\op{\rho}\)) instead:(284)#\[\Entropy(\op{\rho}) = \trace[\op{\rho}\log_\Base\op{\rho}].\]Here, \(\Base\) represents
base
, which is the dimensionality of the unit of information with which the entropy is measured.- Parameters:
state (mat | QuantumObject) – The given state.
base (num) – The dimensionality of the unit of information with which the entropy is measured. Defaults to
2
.
- Returns:
num | sym – The (relative) von Neumann entropy.
Examples
>>> state_A = QuantumState( ... spec=[("a", [0]), ("b", [1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("c", [0]), ("d", [1])], ... form="vector", ... symbols={"c": {"complex": True}, "d": {"complex": True}}, ... conditions=[("c*conjugate(c) + d*conjugate(d)", 1)], ... norm=1, ... ) >>> state_A.entropy() 0 >>> state_B.entropy() 0 >>> state_A.entropy(state_B) 0
>>> state_A = QuantumState( ... spec=[("p", [0]), ("1 - p", [1])], ... kind="mixed", ... symbols={"p": {"positive": True}}, ... norm=1, ... ) >>> state_B = QuantumState( ... spec=[("q", [0]), ("1 - q", [1])], ... kind="mixed", ... symbols={"q": {"positive": True}}, ... norm=1, ... ) >>> state_A.entropy() (-p*log(p) + (p - 1)*log(1 - p))/log(2) >>> state_B.entropy() (-q*log(q) + (q - 1)*log(1 - q))/log(2) >>> state_A.entropy(state_B) (-(p - 1)*(log(1 - p) - log(1 - q)) + log((p/q)**p))/log(2)
- QuantumState.mutual(
- systems_A: int | list[int],
- systems_B: int | list[int] | None = None,
Calculate the mutual information (\(\MutualInformation\)) between two subsystems
systems_A
(\(A\)) andsystems_B
(\(B\)) of the internal state (\(\rho^{A,B}\)):(285)#\[\MutualInformation(A : B) = \Entropy(\op{\rho}^A) + \Entropy(\op{\rho}^B) - \Entropy(\op{\rho}^{A,B})\]where \(\Entropy(\op{\rho})\) is the von Neumann entropy of a state \(\op{\rho}\).
- Parameters:
systems_A (int | list[int]) – The indices of the first subsystem. Defaults to
[0]
.systems_B (int | list[int]) – The indices of the second subsystem. Defaults to the complement of
systems_A
with respect to the entire composition of subsystems ofstate
.dim (int) – The dimensionality of the composite quantum system (and its subsystems). Must be a non-negative integer. Defaults to
2
.
- Returns:
num | sym – The mutual information between the subsystems
systems_A
andsystems_B
of the internal state.
Examples
>>> state_AB = QuantumState( ... spec=[("a", [0, 0]), ("b", [1, 1])], ... form="vector", ... symbols={"a": {"complex": True}, "b": {"complex": True}}, ... conditions=[("a*conjugate(a) + b*conjugate(b)", 1)], ... norm=1, ... ) >>> state_AB.mutual([0], [1]) 2*(-a*log(a*conjugate(a))*conjugate(a) - b*log(b*conjugate(b))*conjugate(b))/log(2)
>>> state_AB = QuantumState( ... spec=[("a", [0, 0]), ("b", [1, 1])], ... kind="mixed", ... symbols={"a": {"positive": True}, "b": {"positive": True}}, ... conditions=[("a + b", 1)], ... norm=1, ... ) >>> state_AB.mutual([0], [1]) (-a*log(a) - b*log(b))/log(2)
Subclasses#
- class VectorState(
- *args,
- **kwargs,
A specialized subclass for creating vector states and storing their metadata.
This is a wrapper on the
QuantumState
class, and so inherits all of its attributes, properties, and methods. The distinction is that thisVectorState
class fixes both theform
andkind
arguments to the values of"vector"
and"pure"
, respectively, at instantiation. This means that neither*args
or**kwargs
must contain these arguments.Examples
>>> qubit_vector = VectorState(spec=[(1, [0]), (1, [1])], norm=1) >>> qubit_vector.print() |ψ⟩ = sqrt(2)/2|0⟩ + sqrt(2)/2|1⟩
- class MatrixState(
- *args,
- **kwargs,
A specialized subclass for creating matrix states and storing their metadata.
This is a wrapper on the
QuantumState
class, and so inherits all of its attributes, properties, and methods. The distinction is that thisMatrixState
class fixes theform
argument to a value of"matrix"
at instantiation. This means that neither*args
or**kwargs
must contain this argument.Examples
>>> qubit_matrix_pure = MatrixState(spec=[(1, [0]), (1, [1])], kind="pure", norm=1) >>> qubit_matrix_pure.print() |ψ⟩⟨ψ| = 1/2|0⟩⟨0| + 1/2|0⟩⟨1| + 1/2|1⟩⟨0| + 1/2|1⟩⟨1|
>>> qubit_matrix_mixed = MatrixState(spec=[(1, [0]), (1, [1])], kind="mixed", norm=1) >>> qubit_matrix_mixed.print() ρ = 1/2|0⟩⟨0| + 1/2|1⟩⟨1|
- class PureState(
- *args,
- **kwargs,
A specialized subclass for creating pure states and storing their metadata.
This is a wrapper on the
QuantumState
class, and so inherits all of its attributes, properties, and methods. The distinction is that thisPureState
class fixes thekind
argument to a value of"pure"
at instantiation. This means that neither*args
or**kwargs
must contain this argument.Examples
>>> qubit_pure_vector = PureState(spec=[(1, [0]), (1, [1])], form="vector", norm=1) >>> qubit_pure_vector.print() |ψ⟩ = sqrt(2)/2|0⟩ + sqrt(2)/2|1⟩
>>> qubit_pure_matrix = PureState(spec=[(1, [0]), (1, [1])], form="matrix", norm=1) >>> qubit_pure_matrix.print() |ψ⟩⟨ψ| = 1/2|0⟩⟨0| + 1/2|0⟩⟨1| + 1/2|1⟩⟨0| + 1/2|1⟩⟨1|
- class MixedState(
- *args,
- **kwargs,
A specialized subclass for creating mixed states and storing their metadata.
This is a wrapper on the
QuantumState
class, and so inherits all of its attributes, properties, and methods. The distinction is that thisMixedState
class fixes both theform
andkind
arguments to the values of"matrix"
and"mixed"
, respectively, at instantiation. This means that neither*args
or**kwargs
must contain these arguments.Examples
>>> qubit_mixed = MixedState(spec=[(1, [0]), (1, [1])], norm=1) >>> qubit_mixed.print() ρ = 1/2|0⟩⟨0| + 1/2|1⟩⟨1|