tensorcircuit.quantum

Quantum state and operator class backend by tensornetwork

class tensorcircuit.quantum.LinearOperator(shape: Sequence[int], matvec: Callable[[Any], Any], dtype: Any = None)[source]

Bases: object

Lightweight linear-operator wrapper for matrix-free matrix-vector products.

Parameters:
  • shape (Sequence[int]) – Operator shape.

  • matvec (Callable[[Tensor], Tensor]) – Function implementing A @ v.

  • dtype (Any, optional) – Optional operator dtype.

__init__(shape: Sequence[int], matvec: Callable[[Any], Any], dtype: Any = None)[source]
matvec(vector: Any) Any[source]

Apply the operator to one vector.

Parameters:

vector (Tensor) – Input vector.

Returns:

Matrix-vector product.

Return type:

Tensor

tensorcircuit.quantum.PauliString2COO(l: Sequence[int], weight: float | None = None) Any[source]

Generate sparse matrix from Pauli string sum

Parameters:
  • l (Sequence[int]) – 1D Tensor representing for a Pauli string, e.g. [1, 0, 0, 3, 2] is for \(X_0Z_3Y_4\)

  • weight (Optional[float], optional) – the weight for the Pauli string defaults to None (all Pauli strings weight 1.0)

Returns:

the tensorflow sparse matrix

Return type:

Tensor

tensorcircuit.quantum.PauliStringSum2COO(ls: Sequence[Sequence[int]], weight: Sequence[float] | None = None, numpy: bool = False) Any[source]

Generate sparse tensor from Pauli string sum. Works with any backend; set numpy=True to obtain a scipy sparse matrix.

Parameters:
  • ls (Sequence[Sequence[int]]) – 2D Tensor, each row is for a Pauli string, e.g. [1, 0, 0, 3, 2] is for \(X_0Z_3Y_4\)

  • weight (Optional[Sequence[float]], optional) – 1D Tensor, each element corresponds the weight for each Pauli string defaults to None (all Pauli strings weight 1.0)

  • numpy (bool) – default False. If True, return numpy coo else return backend compatible sparse tensor

Returns:

the scipy coo sparse matrix

Return type:

Tensor

Note

For structured operators beyond qubit Pauli strings, see TenCirPauli. Its operator layer includes fermionic, bosonic, qudit, and hybrid operators, with sparse and matrix-free targets.

tensorcircuit.quantum.PauliStringSum2COO_numpy(ls: Sequence[Sequence[int]], weight: Sequence[float] | None = None, *, numpy: bool = True) Any

Generate sparse tensor from Pauli string sum. Works with any backend; set numpy=True to obtain a scipy sparse matrix.

Parameters:
  • ls (Sequence[Sequence[int]]) – 2D Tensor, each row is for a Pauli string, e.g. [1, 0, 0, 3, 2] is for \(X_0Z_3Y_4\)

  • weight (Optional[Sequence[float]], optional) – 1D Tensor, each element corresponds the weight for each Pauli string defaults to None (all Pauli strings weight 1.0)

  • numpy (bool) – default False. If True, return numpy coo else return backend compatible sparse tensor

Returns:

the scipy coo sparse matrix

Return type:

Tensor

Note

For structured operators beyond qubit Pauli strings, see TenCirPauli. Its operator layer includes fermionic, bosonic, qudit, and hybrid operators, with sparse and matrix-free targets.

tensorcircuit.quantum.PauliStringSum2COO_tf(ls: Sequence[Sequence[int]], weight: Sequence[float] | None = None) Any[source]

Generate tensorflow sparse matrix from Pauli string sum [deprecated]

Parameters:
  • ls (Sequence[Sequence[int]]) – 2D Tensor, each row is for a Pauli string, e.g. [1, 0, 0, 3, 2] is for \(X_0Z_3Y_4\)

  • weight (Optional[Sequence[float]], optional) – 1D Tensor, each element corresponds the weight for each Pauli string defaults to None (all Pauli strings weight 1.0)

Returns:

the tensorflow coo sparse matrix

Return type:

Tensor

tensorcircuit.quantum.PauliStringSum2Dense(ls: Sequence[Sequence[int]], weight: Sequence[float] | None = None, numpy: bool = False) Any[source]

Generate dense matrix from Pauli string sum. Works with any backend; set numpy=True to obtain a numpy matrix.

Parameters:
  • ls (Sequence[Sequence[int]]) – 2D Tensor, each row is for a Pauli string, e.g. [1, 0, 0, 3, 2] is for \(X_0Z_3Y_4\)

  • weight (Optional[Sequence[float]], optional) – 1D Tensor, each element corresponds the weight for each Pauli string defaults to None (all Pauli strings weight 1.0)

  • numpy (bool) – default False. If True, return numpy coo else return backend compatible sparse tensor

Returns:

the tensorflow dense matrix

Return type:

Tensor

tensorcircuit.quantum.PauliStringSum2MVP(structures: Sequence[Sequence[int]], weights: Sequence[float]) Callable[[Any], Any][source]

Generate a matrix-vector product function for a given Pauli string sum. The returned function mvp(psi) computes sum(w_i * P_i * psi). This implementation efficiently handles the operation by using backend-agnostic slicing (for X/Y flips) and broadcasting (for Z/Y phases), avoiding explicit matrix construction.

Parameters:
  • structures (Sequence[Sequence[int]]) – List of Pauli strings, e.g. [[1, 0, 3], [0, 2, 0]] for X0 Z2 and Y1. (0: I, 1: X, 2: Y, 3: Z)

  • weights (Sequence[float]) – List of weights for each Pauli string.

Returns:

MVP function taking wavefunction (shape [2**n] or [2]*n) and returning the same shape.

Return type:

Callable[[Tensor], Tensor]

Note

For a Rust-native Pauli matrix-vector product implementation for larger or more irregular Pauli workloads, see TenCirPauli. Its structured-operator support extends beyond qubit Pauli strings to fermionic, bosonic, qudit, and hybrid operators.

class tensorcircuit.quantum.QuAdjointVector(subsystem_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None)[source]

Bases: QuOperator

Represents an adjoint (row) vector via a tensor network.

__init__(subsystem_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None) None[source]

Constructs a new QuAdjointVector from a tensor network. This encapsulates an existing tensor network, interpreting it as an adjoint vector (row vector).

Parameters:
  • subsystem_edges (Sequence[Edge]) – The edges of the network to be used as the input edges.

  • ref_nodes (Optional[Collection[AbstractNode]], optional) – Nodes used to refer to parts of the tensor network that are not connected to any input or output edges (for example: a scalar factor).

  • ignore_edges (Optional[Collection[Edge]], optional) – Optional collection of edges to ignore when performing consistency checks.

adjoint() QuOperator

The adjoint of the operator. This creates a new QuOperator with complex-conjugate copies of all tensors in the network and with the input and output edges switched.

Returns:

The adjoint of the operator.

Return type:

QuOperator

check_network() None

Check that the network has the expected dimensionality. This checks that all input and output edges are dangling and that there are no other dangling edges (except any specified in ignore_edges). If not, an exception is raised.

contract(final_edge_order: Sequence[Edge] | None = None) QuOperator

Contract the tensor network in place. This modifies the tensor network representation of the operator (or vector, or scalar), reducing it to a single tensor, without changing the value.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor.

Returns:

The present object.

Return type:

QuOperator

copy() QuOperator

The deep copy of the operator.

Returns:

The new copy of the operator.

Return type:

QuOperator

eval(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor. Note that this modifies the tensor network representing the operator. The default ordering for the axes of the final tensor is: *out_edges, *in_edges. If there are any “ignored” edges, their axes come first: *ignored_edges, *out_edges, *in_edges.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The final tensor representing the operator.

Return type:

Tensor

eval_matrix(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor in two dimentional matrix. The default ordering for the axes of the final tensor is: (\(\prod\) dimension of out_edges, \(\prod\) dimension of in_edges)

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The two-dimentional tensor representing the operator.

Return type:

Tensor

classmethod from_local_tensor(tensor: Any, space: Sequence[int], loc: Sequence[int], out_axes: Sequence[int] | None = None, in_axes: Sequence[int] | None = None) QuOperator
classmethod from_tensor(tensor: Any, subsystem_axes: Sequence[int] | None = None) QuAdjointVector[source]

Construct a QuAdjointVector directly from a single tensor. This first wraps the tensor in a Node, then constructs the QuAdjointVector from that Node.

Example:

def show_attributes(op):
    print(f"op.is_scalar() \t\t-> {op.is_scalar()}")
    print(f"op.is_vector() \t\t-> {op.is_vector()}")
    print(f"op.is_adjoint_vector() \t-> {op.is_adjoint_vector()}")
    print(f"op.eval() \n{op.eval()}")
>>> psi_tensor = np.random.rand(2, 2)
>>> psi_tensor
array([[0.27260127, 0.91401091],
       [0.06490953, 0.38653646]])
>>> op = qu.QuAdjointVector.from_tensor(psi_tensor, [0, 1])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> False
op.is_adjoint_vector()  -> True
op.eval()
[[0.27260127 0.91401091]
 [0.06490953 0.38653646]]
Parameters:
  • tensor (Tensor) – The tensor for constructing an QuAdjointVector.

  • subsystem_axes (Optional[Sequence[int]], optional) – Sequence of integer indices specifying the order in which to interpret the axes as subsystems (input edges). If not specified, the axes are taken in ascending order.

Returns:

The new constructed QuAdjointVector give from the given tensor.

Return type:

QuAdjointVector

property in_space: List[int]
is_adjoint_vector() bool

Returns a bool indicating if QuOperator is an adjoint vector. Examples can be found in the QuOperator.from_tensor.

is_scalar() bool

Returns a bool indicating if QuOperator is a scalar. Examples can be found in the QuOperator.from_tensor.

is_vector() bool

Returns a bool indicating if QuOperator is a vector. Examples can be found in the QuOperator.from_tensor.

property nodes: List[AbstractNode]

All tensor-network nodes involved in the operator.

norm() QuScalar

The squared Hilbert-Schmidt norm of the operator as a lazy QuScalar; call .eval() for a number and take sqrt for the actual norm.

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator

The partial trace of the operator. Subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given; the other is inferred as the complement over range(len(self.in_edges)). Out-of-range and duplicate indices raise ValueError with the offending value.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

A new QuOperator or QuScalar representing the result.

Return type:

QuOperator

projector() QuOperator[source]

The projector of the operator. The operator, as a linear operator, on the adjoint of the operator.

Set \(A\) is the operator in matrix form, then the projector of operator is defined as: \(A^\dagger A\)

Returns:

The projector of the operator.

Return type:

QuOperator

reduced_density(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator[source]

The reduced density of the operator.

Set \(A\) is the matrix of the operator, then the reduced density is defined as:

\[\mathrm{Tr}_{subsystems}(A^\dagger A)\]

Firstly, take the projector of the operator, then trace out the subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given. See QuOperator.partial_trace() for the resolution and validation semantics.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

The QuOperator of the reduced density of the operator with given subsystems.

Return type:

QuOperator

property space: List[int]
property subsystem_edges: List[Edge]
tensor_product(other: QuOperator) QuOperator

Tensor product with another operator. Given two operators A and B, produces a new operator AB representing \(A \otimes B\). The out_edges (in_edges) of AB is simply the concatenation of the out_edges (in_edges) of A.copy() with that of B.copy(): new_out_edges = [*out_edges_A_copy, *out_edges_B_copy] new_in_edges = [*in_edges_A_copy, *in_edges_B_copy]

Example:

>>> psi = qu.QuVector.from_tensor(np.random.rand(2, 2))
>>> psi_psi = psi.tensor_product(psi)
>>> len(psi_psi.subsystem_edges)
4
>>> float(psi_psi.norm().eval())
2.9887872748523585
>>> psi.norm().eval() ** 2
2.9887872748523585
Parameters:

other (QuOperator) – The other operator (B).

Returns:

The result (AB).

Return type:

QuOperator

trace() QuScalar

The trace of the operator as a lazy QuScalar; call .eval() for a number.

class tensorcircuit.quantum.QuOperator(out_edges: Sequence[Edge], in_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None)[source]

Bases: object

Represents a linear operator via a tensor network. To interpret a tensor network as a linear operator, some of the dangling edges must be designated as out_edges (output edges) and the rest as in_edges (input edges). Considered as a matrix, the out_edges represent the row index and the in_edges represent the column index. The (right) action of the operator on another then consists of connecting the in_edges of the first operator to the out_edges of the second. Can be used to do simple linear algebra with tensor networks.

__init__(out_edges: Sequence[Edge], in_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None) None[source]

Creates a new QuOperator from a tensor network. This encapsulates an existing tensor network, interpreting it as a linear operator. The network is checked for consistency: All dangling edges must either be in out_edges, in_edges, or ignore_edges.

Parameters:
  • out_edges (Sequence[Edge]) – The edges of the network to be used as the output edges.

  • in_edges (Sequence[Edge]) – The edges of the network to be used as the input edges.

  • ref_nodes (Optional[Collection[AbstractNode]], optional) – Nodes used to refer to parts of the tensor network that are not connected to any input or output edges (for example: a scalar factor).

  • ignore_edges (Optional[Collection[Edge]], optional) – Optional collection of dangling edges to ignore when performing consistency checks.

Raises:

ValueError – At least one reference node is required to specify a scalar. None provided!

adjoint() QuOperator[source]

The adjoint of the operator. This creates a new QuOperator with complex-conjugate copies of all tensors in the network and with the input and output edges switched.

Returns:

The adjoint of the operator.

Return type:

QuOperator

check_network() None[source]

Check that the network has the expected dimensionality. This checks that all input and output edges are dangling and that there are no other dangling edges (except any specified in ignore_edges). If not, an exception is raised.

contract(final_edge_order: Sequence[Edge] | None = None) QuOperator[source]

Contract the tensor network in place. This modifies the tensor network representation of the operator (or vector, or scalar), reducing it to a single tensor, without changing the value.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor.

Returns:

The present object.

Return type:

QuOperator

copy() QuOperator[source]

The deep copy of the operator.

Returns:

The new copy of the operator.

Return type:

QuOperator

eval(final_edge_order: Sequence[Edge] | None = None) Any[source]

Contracts the tensor network in place and returns the final tensor. Note that this modifies the tensor network representing the operator. The default ordering for the axes of the final tensor is: *out_edges, *in_edges. If there are any “ignored” edges, their axes come first: *ignored_edges, *out_edges, *in_edges.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The final tensor representing the operator.

Return type:

Tensor

eval_matrix(final_edge_order: Sequence[Edge] | None = None) Any[source]

Contracts the tensor network in place and returns the final tensor in two dimentional matrix. The default ordering for the axes of the final tensor is: (\(\prod\) dimension of out_edges, \(\prod\) dimension of in_edges)

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The two-dimentional tensor representing the operator.

Return type:

Tensor

classmethod from_local_tensor(tensor: Any, space: Sequence[int], loc: Sequence[int], out_axes: Sequence[int] | None = None, in_axes: Sequence[int] | None = None) QuOperator[source]
classmethod from_tensor(tensor: Any, out_axes: Sequence[int] | None = None, in_axes: Sequence[int] | None = None) QuOperator[source]

Construct a QuOperator directly from a single tensor. This first wraps the tensor in a Node, then constructs the QuOperator from that Node.

Example:

def show_attributes(op):
    print(f"op.is_scalar() \t\t-> {op.is_scalar()}")
    print(f"op.is_vector() \t\t-> {op.is_vector()}")
    print(f"op.is_adjoint_vector() \t-> {op.is_adjoint_vector()}")
    print(f"op.eval() \n{op.eval()}")
>>> psi_tensor = np.random.rand(2, 2)
>>> psi_tensor
array([[0.27260127, 0.91401091],
       [0.06490953, 0.38653646]])
>>> op = qu.QuOperator.from_tensor(psi_tensor, out_axes=[0], in_axes=[1])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> False
op.is_adjoint_vector()  -> False
op.eval()
[[0.27260127 0.91401091]
 [0.06490953 0.38653646]]
Parameters:
  • tensor (Tensor) – The tensor.

  • out_axes (Optional[Sequence[int]], optional) – The axis indices of tensor to use as out_edges.

  • in_axes (Optional[Sequence[int]], optional) – The axis indices of tensor to use as in_edges.

Returns:

The new operator.

Return type:

QuOperator

property in_space: List[int]
is_adjoint_vector() bool[source]

Returns a bool indicating if QuOperator is an adjoint vector. Examples can be found in the QuOperator.from_tensor.

is_scalar() bool[source]

Returns a bool indicating if QuOperator is a scalar. Examples can be found in the QuOperator.from_tensor.

is_vector() bool[source]

Returns a bool indicating if QuOperator is a vector. Examples can be found in the QuOperator.from_tensor.

property nodes: List[AbstractNode]

All tensor-network nodes involved in the operator.

norm() QuScalar[source]

The squared Hilbert-Schmidt norm of the operator as a lazy QuScalar; call .eval() for a number and take sqrt for the actual norm.

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator[source]

The partial trace of the operator. Subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given; the other is inferred as the complement over range(len(self.in_edges)). Out-of-range and duplicate indices raise ValueError with the offending value.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

A new QuOperator or QuScalar representing the result.

Return type:

QuOperator

tensor_product(other: QuOperator) QuOperator[source]

Tensor product with another operator. Given two operators A and B, produces a new operator AB representing \(A \otimes B\). The out_edges (in_edges) of AB is simply the concatenation of the out_edges (in_edges) of A.copy() with that of B.copy(): new_out_edges = [*out_edges_A_copy, *out_edges_B_copy] new_in_edges = [*in_edges_A_copy, *in_edges_B_copy]

Example:

>>> psi = qu.QuVector.from_tensor(np.random.rand(2, 2))
>>> psi_psi = psi.tensor_product(psi)
>>> len(psi_psi.subsystem_edges)
4
>>> float(psi_psi.norm().eval())
2.9887872748523585
>>> psi.norm().eval() ** 2
2.9887872748523585
Parameters:

other (QuOperator) – The other operator (B).

Returns:

The result (AB).

Return type:

QuOperator

trace() QuScalar[source]

The trace of the operator as a lazy QuScalar; call .eval() for a number.

class tensorcircuit.quantum.QuScalar(ref_nodes: Collection[AbstractNode], ignore_edges: Collection[Edge] | None = None)[source]

Bases: QuOperator

Represents a scalar via a tensor network.

__init__(ref_nodes: Collection[AbstractNode], ignore_edges: Collection[Edge] | None = None) None[source]

Constructs a new QuScalar from a tensor network. This encapsulates an existing tensor network, interpreting it as a scalar.

Parameters:
  • ref_nodes (Collection[AbstractNode]) – Nodes used to refer to the tensor network (need not be exhaustive - one node from each disconnected subnetwork is sufficient).

  • ignore_edges (Optional[Collection[Edge]], optional) – Optional collection of edges to ignore when performing consistency checks.

adjoint() QuOperator

The adjoint of the operator. This creates a new QuOperator with complex-conjugate copies of all tensors in the network and with the input and output edges switched.

Returns:

The adjoint of the operator.

Return type:

QuOperator

check_network() None

Check that the network has the expected dimensionality. This checks that all input and output edges are dangling and that there are no other dangling edges (except any specified in ignore_edges). If not, an exception is raised.

contract(final_edge_order: Sequence[Edge] | None = None) QuOperator

Contract the tensor network in place. This modifies the tensor network representation of the operator (or vector, or scalar), reducing it to a single tensor, without changing the value.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor.

Returns:

The present object.

Return type:

QuOperator

copy() QuOperator

The deep copy of the operator.

Returns:

The new copy of the operator.

Return type:

QuOperator

eval(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor. Note that this modifies the tensor network representing the operator. The default ordering for the axes of the final tensor is: *out_edges, *in_edges. If there are any “ignored” edges, their axes come first: *ignored_edges, *out_edges, *in_edges.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The final tensor representing the operator.

Return type:

Tensor

eval_matrix(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor in two dimentional matrix. The default ordering for the axes of the final tensor is: (\(\prod\) dimension of out_edges, \(\prod\) dimension of in_edges)

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The two-dimentional tensor representing the operator.

Return type:

Tensor

classmethod from_local_tensor(tensor: Any, space: Sequence[int], loc: Sequence[int], out_axes: Sequence[int] | None = None, in_axes: Sequence[int] | None = None) QuOperator
classmethod from_tensor(tensor: Any) QuScalar[source]

Construct a QuScalar directly from a single tensor. This first wraps the tensor in a Node, then constructs the QuScalar from that Node.

Example:

def show_attributes(op):
    print(f"op.is_scalar() \t\t-> {op.is_scalar()}")
    print(f"op.is_vector() \t\t-> {op.is_vector()}")
    print(f"op.is_adjoint_vector() \t-> {op.is_adjoint_vector()}")
    print(f"op.eval() \n{op.eval()}")
>>> op = qu.QuScalar.from_tensor(1.0)
>>> show_attributes(op)
op.is_scalar()          -> True
op.is_vector()          -> False
op.is_adjoint_vector()  -> False
op.eval()
1.0
Parameters:

tensor (Tensor) – The tensor for constructing a new QuScalar.

Returns:

The new constructed QuScalar from the given tensor.

Return type:

QuScalar

property in_space: List[int]
is_adjoint_vector() bool

Returns a bool indicating if QuOperator is an adjoint vector. Examples can be found in the QuOperator.from_tensor.

is_scalar() bool

Returns a bool indicating if QuOperator is a scalar. Examples can be found in the QuOperator.from_tensor.

is_vector() bool

Returns a bool indicating if QuOperator is a vector. Examples can be found in the QuOperator.from_tensor.

property nodes: List[AbstractNode]

All tensor-network nodes involved in the operator.

norm() QuScalar

The squared Hilbert-Schmidt norm of the operator as a lazy QuScalar; call .eval() for a number and take sqrt for the actual norm.

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator

The partial trace of the operator. Subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given; the other is inferred as the complement over range(len(self.in_edges)). Out-of-range and duplicate indices raise ValueError with the offending value.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

A new QuOperator or QuScalar representing the result.

Return type:

QuOperator

tensor_product(other: QuOperator) QuOperator

Tensor product with another operator. Given two operators A and B, produces a new operator AB representing \(A \otimes B\). The out_edges (in_edges) of AB is simply the concatenation of the out_edges (in_edges) of A.copy() with that of B.copy(): new_out_edges = [*out_edges_A_copy, *out_edges_B_copy] new_in_edges = [*in_edges_A_copy, *in_edges_B_copy]

Example:

>>> psi = qu.QuVector.from_tensor(np.random.rand(2, 2))
>>> psi_psi = psi.tensor_product(psi)
>>> len(psi_psi.subsystem_edges)
4
>>> float(psi_psi.norm().eval())
2.9887872748523585
>>> psi.norm().eval() ** 2
2.9887872748523585
Parameters:

other (QuOperator) – The other operator (B).

Returns:

The result (AB).

Return type:

QuOperator

trace() QuScalar

The trace of the operator as a lazy QuScalar; call .eval() for a number.

class tensorcircuit.quantum.QuVector(subsystem_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None)[source]

Bases: QuOperator

Represents a (column) vector via a tensor network.

__init__(subsystem_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None) None[source]

Constructs a new QuVector from a tensor network. This encapsulates an existing tensor network, interpreting it as a (column) vector.

Parameters:
  • subsystem_edges (Sequence[Edge]) – The edges of the network to be used as the output edges.

  • ref_nodes (Optional[Collection[AbstractNode]], optional) – Nodes used to refer to parts of the tensor network that are not connected to any input or output edges (for example: a scalar factor).

  • ignore_edges (Optional[Collection[Edge]], optional) – Optional collection of edges to ignore when performing consistency checks.

adjoint() QuOperator

The adjoint of the operator. This creates a new QuOperator with complex-conjugate copies of all tensors in the network and with the input and output edges switched.

Returns:

The adjoint of the operator.

Return type:

QuOperator

check_network() None

Check that the network has the expected dimensionality. This checks that all input and output edges are dangling and that there are no other dangling edges (except any specified in ignore_edges). If not, an exception is raised.

contract(final_edge_order: Sequence[Edge] | None = None) QuOperator

Contract the tensor network in place. This modifies the tensor network representation of the operator (or vector, or scalar), reducing it to a single tensor, without changing the value.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor.

Returns:

The present object.

Return type:

QuOperator

copy() QuOperator

The deep copy of the operator.

Returns:

The new copy of the operator.

Return type:

QuOperator

eval(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor. Note that this modifies the tensor network representing the operator. The default ordering for the axes of the final tensor is: *out_edges, *in_edges. If there are any “ignored” edges, their axes come first: *ignored_edges, *out_edges, *in_edges.

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The final tensor representing the operator.

Return type:

Tensor

eval_matrix(final_edge_order: Sequence[Edge] | None = None) Any

Contracts the tensor network in place and returns the final tensor in two dimentional matrix. The default ordering for the axes of the final tensor is: (\(\prod\) dimension of out_edges, \(\prod\) dimension of in_edges)

Parameters:

final_edge_order (Optional[Sequence[Edge]], optional) – Manually specify the axis ordering of the final tensor. The default ordering is determined by out_edges and in_edges (see above).

Raises:

ValueError – Node count ‘{}’ > 1 after contraction!

Returns:

The two-dimentional tensor representing the operator.

Return type:

Tensor

classmethod from_local_tensor(tensor: Any, space: Sequence[int], loc: Sequence[int], out_axes: Sequence[int] | None = None, in_axes: Sequence[int] | None = None) QuOperator
classmethod from_tensor(tensor: Any, subsystem_axes: Sequence[int] | None = None) QuVector[source]

Construct a QuVector directly from a single tensor. This first wraps the tensor in a Node, then constructs the QuVector from that Node.

Example:

def show_attributes(op):
    print(f"op.is_scalar() \t\t-> {op.is_scalar()}")
    print(f"op.is_vector() \t\t-> {op.is_vector()}")
    print(f"op.is_adjoint_vector() \t-> {op.is_adjoint_vector()}")
    print(f"op.eval() \n{op.eval()}")
>>> psi_tensor = np.random.rand(2, 2)
>>> psi_tensor
array([[0.27260127, 0.91401091],
       [0.06490953, 0.38653646]])
>>> op = qu.QuVector.from_tensor(psi_tensor, [0, 1])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> True
op.is_adjoint_vector()  -> False
op.eval()
[[0.27260127 0.91401091]
 [0.06490953 0.38653646]]
Parameters:
  • tensor (Tensor) – The tensor for constructing a “QuVector”.

  • subsystem_axes (Optional[Sequence[int]], optional) – Sequence of integer indices specifying the order in which to interpret the axes as subsystems (output edges). If not specified, the axes are taken in ascending order.

Returns:

The new constructed QuVector from the given tensor.

Return type:

QuVector

property in_space: List[int]
is_adjoint_vector() bool

Returns a bool indicating if QuOperator is an adjoint vector. Examples can be found in the QuOperator.from_tensor.

is_scalar() bool

Returns a bool indicating if QuOperator is a scalar. Examples can be found in the QuOperator.from_tensor.

is_vector() bool

Returns a bool indicating if QuOperator is a vector. Examples can be found in the QuOperator.from_tensor.

property nodes: List[AbstractNode]

All tensor-network nodes involved in the operator.

norm() QuScalar

The squared Hilbert-Schmidt norm of the operator as a lazy QuScalar; call .eval() for a number and take sqrt for the actual norm.

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator

The partial trace of the operator. Subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given; the other is inferred as the complement over range(len(self.in_edges)). Out-of-range and duplicate indices raise ValueError with the offending value.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

A new QuOperator or QuScalar representing the result.

Return type:

QuOperator

projector() QuOperator[source]

The projector of the operator. The operator, as a linear operator, on the adjoint of the operator.

Set \(A\) is the operator in matrix form, then the projector of operator is defined as: \(A A^\dagger\)

Returns:

The projector of the operator.

Return type:

QuOperator

reduced_density(subsystems_to_trace_out: Sequence[int] | None = None, *, subsystem_to_keep: Sequence[int] | None = None) QuOperator[source]

The reduced density of the operator.

Set \(A\) is the matrix of the operator, then the reduced density is defined as:

\[\mathrm{Tr}_{subsystems}(A A^\dagger)\]

Firstly, take the projector of the operator, then trace out the subsystems to trace out are supplied as indices, so that dangling edges are connected to each other as: out_edges[i] ^ in_edges[i] for i in subsystems_to_trace_out This does not modify the original network. The original ordering of the remaining subsystems is maintained.

Exactly one of subsystems_to_trace_out (legacy, positional) or subsystem_to_keep must be given. See QuOperator.partial_trace() for the resolution and validation semantics.

Parameters:
  • subsystems_to_trace_out (Optional[Sequence[int]]) – Indices of subsystems to trace out.

  • subsystem_to_keep (Optional[Sequence[int]]) – Indices of subsystems to keep (complement is traced out). Mutually exclusive with subsystems_to_trace_out.

Returns:

The QuOperator of the reduced density of the operator with given subsystems.

Return type:

QuOperator

property space: List[int]
property subsystem_edges: List[Edge]
tensor_product(other: QuOperator) QuOperator

Tensor product with another operator. Given two operators A and B, produces a new operator AB representing \(A \otimes B\). The out_edges (in_edges) of AB is simply the concatenation of the out_edges (in_edges) of A.copy() with that of B.copy(): new_out_edges = [*out_edges_A_copy, *out_edges_B_copy] new_in_edges = [*in_edges_A_copy, *in_edges_B_copy]

Example:

>>> psi = qu.QuVector.from_tensor(np.random.rand(2, 2))
>>> psi_psi = psi.tensor_product(psi)
>>> len(psi_psi.subsystem_edges)
4
>>> float(psi_psi.norm().eval())
2.9887872748523585
>>> psi.norm().eval() ** 2
2.9887872748523585
Parameters:

other (QuOperator) – The other operator (B).

Returns:

The result (AB).

Return type:

QuOperator

trace() QuScalar

The trace of the operator as a lazy QuScalar; call .eval() for a number.

tensorcircuit.quantum.anti_flatness(rho: Any | QuOperator) Any[source]

Compute the anti-flatness of a normalized density matrix.

For the eigenvalues \(\lambda_i\) of rho, anti-flatness is

\[\mathcal{F} = \operatorname{Tr}(\rho^3) - \left[\operatorname{Tr}(\rho^2)\right]^2.\]

The input is expected to be a square, trace-one density matrix. The expression is evaluated with matrix products rather than an eigendecomposition, so it remains differentiable and compatible with backend JIT transforms. Anti-flatness is zero for a rank-one spectrum and for a flat spectrum on its support; it is a spectral diagnostic, not by itself a complete non-stabilizerness measure.

Parameters:

rho (Union[Tensor, QuOperator]) – The normalized density matrix in form of Tensor or QuOperator.

Returns:

The anti-flatness of the density matrix.

Return type:

Tensor

tensorcircuit.quantum.aslinearoperator(operator: Any, shape: Sequence[int] | None = None, dtype: Any = None) LinearOperator[source]

Convert a dense matrix, sparse matrix, or MVP callable to a linear operator.

MVP callables must implement matvec(vector) -> A @ vector. When a bare callable is supplied, shape must be provided because callables do not carry matrix metadata.

Parameters:
  • operator (Any) – Dense matrix, sparse matrix, existing LinearOperator, or MVP callable.

  • shape (Sequence[int], optional) – Optional operator shape. Required for bare callables.

  • dtype (Any, optional) – Optional operator dtype.

Returns:

Linear operator.

Return type:

LinearOperator

tensorcircuit.quantum.check_spaces(edges_1: Sequence[Edge], edges_2: Sequence[Edge]) None[source]

Check the vector spaces represented by two lists of edges are compatible. The number of edges must be the same and the dimensions of each pair of edges must match. Otherwise, an exception is raised.

Parameters:
  • edges_1 (Sequence[Edge]) – List of edges representing a many-body Hilbert space.

  • edges_2 (Sequence[Edge]) – List of edges representing a many-body Hilbert space.

Raises:

ValueError – Hilbert-space mismatch: “Cannot connect {} subsystems with {} subsystems”, or “Input dimension {} != output dimension {}.”

tensorcircuit.quantum.correlation_from_counts(index: Sequence[int], results: Any) Any[source]

Compute \(\prod_{i\in \\text{index}} s_i\), where the (unnormalized) counts for each bitstring are given as a vector results. results is in the format of “count_vector” and is normalized internally.

Example:

>>> prob = tc.array_to_tensor(np.array([0.6, 0.4, 0, 0]))
>>> qu.correlation_from_counts([0, 1], prob)
(0.20000002+0j)
>>> qu.correlation_from_counts([1], prob)
(0.20000002+0j)
Parameters:
  • index (Sequence[int]) – list of int, indicating the position in the bitstring

  • results (Tensor) – count vector of shape 2^n (normalized internally to a probability vector)

Returns:

Correlation expectation from measurement shots.

Return type:

Tensor

tensorcircuit.quantum.correlation_from_samples(index: Sequence[int], results: Any, n: int) Any[source]

Compute \(\prod_{i\in \\text{index}} s_i (s=\pm 1)\), Results is in the format of “sample_int” or “sample_bin”

Parameters:
  • index (Sequence[int]) – list of int, indicating the position in the bitstring

  • results (Tensor) – sample tensor

  • n (int) – number of qubits

Returns:

Correlation expectation from measurement shots

Return type:

Tensor

tensorcircuit.quantum.count_d2s(drepr: Any, eps: float = 1e-07) Tuple[Any, Any][source]

measurement shots results, dense representation to sparse tuple representation non-jittable due to the non fixed return shape count_tuple to count_vector

Example:

>>> tc.quantum.counts_d2s(np.array([0.1, 0, -0.3, 0.2]))
(array([0, 2, 3]), array([ 0.1, -0.3,  0.2]))
Parameters:
  • drepr (Tensor) – dense count vector of shape [dim**n]

  • eps (float, optional) – cutoff to determine nonzero elements, defaults to 1e-7

Returns:

(indices, values) of entries with absolute value greater than eps

Return type:

Tuple[Tensor, Tensor]

tensorcircuit.quantum.count_s2d(srepr: Tuple[Any, Any], n: int, dim: int | None = None) Any[source]

measurement shots results, sparse tuple representation to dense representation count_vector to count_tuple

Parameters:
  • srepr (Tuple[Tensor, Tensor]) – (indices, values) tuple of nonzero shot-count entries

  • n (int) – number of qubits

  • dim (int, optional) – local Hilbert-space dimension, defaults to None (treated as 2)

Returns:

dense count vector of shape [dim**n]

Return type:

Tensor

tensorcircuit.quantum.count_t2v(drepr: Any, eps: float = 1e-07) Tuple[Any, Any]

measurement shots results, dense representation to sparse tuple representation non-jittable due to the non fixed return shape count_tuple to count_vector

Example:

>>> tc.quantum.counts_d2s(np.array([0.1, 0, -0.3, 0.2]))
(array([0, 2, 3]), array([ 0.1, -0.3,  0.2]))
Parameters:
  • drepr (Tensor) – dense count vector of shape [dim**n]

  • eps (float, optional) – cutoff to determine nonzero elements, defaults to 1e-7

Returns:

(indices, values) of entries with absolute value greater than eps

Return type:

Tuple[Tensor, Tensor]

tensorcircuit.quantum.count_tuple2dict(count: Tuple[Any, Any], n: int, key: str = 'bin', dim: int | None = None) Dict[Any, int][source]

count_tuple to count_dict_bin or count_dict_int

Parameters:
  • count (Tuple[Tensor, Tensor]) – count_tuple format (indices, counts)

  • n (int) – number of sites (qubits or qudits)

  • key (str, optional) – can be “int” or “bin”, defaults to “bin”

  • dim (int, optional) – local dimension, defaults to 2

Returns:

count_dict

Return type:

Dict[Any, int]

tensorcircuit.quantum.count_vector2dict(count: Any, n: int, key: str = 'bin', dim: int | None = None) Dict[Any, int][source]

Convert count_vector to count_dict_bin or count_dict_int. For d>10 cases, a base-d string (0-9A-Z) is used.

Parameters:
  • count (Tensor) – tensor in shape [d**n]

  • n (int) – number of sites

  • key (str, optional) – can be “int” or “bin”, defaults to “bin”

  • dim (int, optional) – local dimension (default 2)

Returns:

mapping from configuration to count

Return type:

Dict[Any, int]

tensorcircuit.quantum.counts_v2t(srepr: Tuple[Any, Any], n: int, dim: int | None = None) Any

measurement shots results, sparse tuple representation to dense representation count_vector to count_tuple

Parameters:
  • srepr (Tuple[Tensor, Tensor]) – (indices, values) tuple of nonzero shot-count entries

  • n (int) – number of qubits

  • dim (int, optional) – local Hilbert-space dimension, defaults to None (treated as 2)

Returns:

dense count vector of shape [dim**n]

Return type:

Tensor

tensorcircuit.quantum.double_state(h: Any, beta: float = 1) Any[source]

Compute the double state of the given Hamiltonian operator h.

Parameters:
  • h (Tensor) – Hamiltonian operator in form of Tensor.

  • beta (float, optional) – Constant for the optimization, default is 1.

Returns:

The double state of h with the given beta.

Return type:

Tensor

tensorcircuit.quantum.eliminate_identities(nodes: Collection[AbstractNode]) Tuple[dict, dict][source]

Eliminates any connected CopyNodes that are identity matrices. This will modify the network represented by nodes. Only identities that are connected to other nodes are eliminated.

Parameters:

nodes (Collection[AbstractNode]) – Collection of nodes to search.

Returns:

The Dictionary mapping remaining Nodes to any replacements, Dictionary specifying all dangling-edge replacements.

Return type:

Dict[Union[CopyNode, AbstractNode], Union[Node, AbstractNode]], Dict[Edge, Edge]

tensorcircuit.quantum.entanglement_anti_flatness(state: Any, *, subsystem_to_keep: Sequence[int] | None = None, subsystems_to_trace_out: Sequence[int] | None = None, dim: int | None = None) Any[source]

Compute the anti-flatness of a subsystem entanglement spectrum.

The subsystem is specified via exactly one of subsystem_to_keep / subsystems_to_trace_out. The argument resolution follows the new subsystem specification used by entanglement_entropy().

Parameters:
  • state (Tensor) – Wavefunction or density matrix of the full system.

  • subsystem_to_keep (Optional[Sequence[int]]) – Sites to keep; all others are traced out.

  • subsystems_to_trace_out (Optional[Sequence[int]]) – Sites to trace out.

  • dim (Optional[int]) – Local qudit dimension, defaulting to 2.

Returns:

The subsystem anti-flatness.

Return type:

Tensor

tensorcircuit.quantum.entanglement_entropy(state: Any, cut: int | List[int] | Tuple[int, ...] | None = None, *, subsystem_to_keep: Sequence[int] | None = None, subsystems_to_trace_out: Sequence[int] | None = None, dim: int | None = None) Any[source]

Compute the von Neumann entanglement entropy of state across the bipartition defined by cut.

The traced-out subsystem can be specified via the legacy cut argument (int = list(range(cut)) i.e. [0, cut); or an explicit site list) or, preferably, via exactly one of subsystem_to_keep / subsystems_to_trace_out. See reduced_density_matrix() for the full resolution semantics; if both cut and a new argument are given, the new argument wins and cut is ignored (with a UserWarning).

Parameters:
  • state (Tensor) – wavefunction or density matrix of the full system

  • cut (Union[int, List[int], Tuple[int, ...], None]) – legacy trace-out specification; prefer the dual arguments below.

  • subsystem_to_keep (Optional[Sequence[int]]) – sites to keep (all others are traced out). Mutually exclusive with subsystems_to_trace_out.

  • subsystems_to_trace_out (Optional[Sequence[int]]) – sites to trace out.

  • dim (Optional[int]) – dimension of qudit system, defaults to 2

Returns:

the von Neumann entanglement entropy \(S = -\mathrm{Tr}(\rho \log\rho)\)

Return type:

Tensor

tensorcircuit.quantum.entanglement_negativity(rho: Any, transposed_sites: List[int], dim: int | None = None) Any[source]

Compute the entanglement negativity of rho across the bipartition defined by transposed_sites.

Parameters:
  • rho (Tensor) – density matrix of the bipartite system

  • transposed_sites (List[int]) – sites to transpose when forming the partial transpose

  • dim (int) – dimension of qudit system

Returns:

the entanglement negativity \((\lVert\rho^{T_A}\rVert_1 - 1)/2\)

Return type:

Tensor

tensorcircuit.quantum.entropy(rho: Any | QuOperator, eps: float | None = None) Any[source]

Compute the entropy from the given density matrix rho.

Example:

@partial(tc.backend.jit, jit_compile=False, static_argnums=(1, 2))
def entanglement1(param, n, nlayers):
    c = tc.Circuit(n)
    c = tc.templates.blocks.example_block(c, param, nlayers)
    w = c.wavefunction()
    rm = qu.reduced_density_matrix(w, int(n / 2))
    return qu.entropy(rm)

@partial(tc.backend.jit, jit_compile=False, static_argnums=(1, 2))
def entanglement2(param, n, nlayers):
    c = tc.Circuit(n)
    c = tc.templates.blocks.example_block(c, param, nlayers)
    w = c.get_quvector()
    rm = w.reduced_density([i for i in range(int(n / 2))])
    return qu.entropy(rm)
>>> param = tc.backend.ones([6, 6])
>>> tc.backend.trace(param)
>>> entanglement1(param, 6, 3)
1.3132654
>>> entanglement2(param, 6, 3)
1.3132653
Parameters:
  • rho (Union[Tensor, QuOperator]) – The density matrix in form of Tensor or QuOperator.

  • eps (float) – Epsilon, default is 1e-12.

Returns:

Entropy on the given density matrix.

Return type:

Tensor

tensorcircuit.quantum.extract_tensors_from_qop(qop: QuOperator) Tuple[List[Node], bool, int][source]

Extract and sort tensors from QuOperator for conversion to other tensor network formats.

Parameters:

qop (QuOperator) – Input QuOperator to extract tensors from

Returns:

Tuple containing (sorted_nodes, is_mps, nwires) where:

  • sorted_nodes: List of Node objects sorted in linear chain order

  • is_mps: Boolean flag indicating if the structure is MPS (True) or MPO (False)

  • nwires: Integer number of physical edges/qubits in the system

Return type:

Tuple[List[Node], bool, int]

tensorcircuit.quantum.fidelity(rho: Any, rho0: Any) Any[source]

Return the squared fidelity scalar between two states rho and rho0.

\[\left( \operatorname{Tr}\left[\sqrt{\sqrt{rho} rho_0 \sqrt{rho}}\right] \right)^2\]

Note

This returns the squared Uhlmann fidelity F**2, not F itself. For the unsquared fidelity, take backend.sqrt of the result.

param rho:

The density matrix in form of Tensor.

type rho:

Tensor

param rho0:

The density matrix in form of Tensor.

type rho0:

Tensor

return:

The squared fidelity scalar between rho and rho0.

rtype:

Tensor

tensorcircuit.quantum.free_energy(rho: Any | QuOperator, h: Any | QuOperator, beta: float = 1, eps: float = 1e-12) Any[source]

Compute the free energy of the given density matrix.

Example:

>>> rho = np.array([[1.0, 0], [0, 0]])
>>> h = np.array([[-1.0, 0], [0, 1]])
>>> qu.free_energy(rho, h, 0.5)
-0.9999999999979998
>>> hq = qu.QuOperator.from_tensor(h)
>>> qu.free_energy(rho, hq, 0.5)
array([[-1.]])
Parameters:
  • rho (Union[Tensor, QuOperator]) – The density matrix in form of Tensor or QuOperator.

  • h (Union[Tensor, QuOperator]) – Hamiltonian operator in form of Tensor or QuOperator.

  • beta (float, optional) – Constant for the optimization, default is 1.

  • eps (float, optional) – Epsilon, default is 1e-12.

Returns:

The free energy of the given density matrix with the Hamiltonian operator.

Return type:

Tensor

tensorcircuit.quantum.generate_local_hamiltonian(*hlist: Sequence[Any], matrix_form: bool = True) QuOperator | Any[source]

Generate a local Hamiltonian operator based on the given sequence of Tensor. Note: further jit is recommended. For large Hilbert space, sparse Hamiltonian is recommended

Parameters:
  • hlist (Sequence[Tensor]) – A sequence of Tensor.

  • matrix_form (bool, optional) – Return Hamiltonian operator in form of matrix, defaults to True.

Returns:

The Hamiltonian operator in form of QuOperator or matrix.

Return type:

Union[QuOperator, Tensor]

tensorcircuit.quantum.get_all_nodes(edges: Iterable[Edge]) List[Node][source]

Return the set of nodes connected to edges.

tensorcircuit.quantum.gibbs_state(h: Any, beta: float = 1) Any[source]

Compute the Gibbs state of the given Hamiltonian operator h.

Parameters:
  • h (Tensor) – Hamiltonian operator in form of Tensor.

  • beta (float, optional) – Constant for the optimization, default is 1.

Returns:

The Gibbs state of h with the given beta.

Return type:

Tensor

tensorcircuit.quantum.heisenberg_hamiltonian(g: Any, hzz: float = 1.0, hxx: float = 1.0, hyy: float = 1.0, hz: float = 0.0, hx: float = 0.0, hy: float = 0.0, sparse: bool = True, numpy: bool = False) Any[source]

Generate Heisenberg Hamiltonian with possible external fields. Works with any backend; set numpy=True to obtain a numpy/scipy matrix.

Example:

>>> g = tc.templates.graphs.Line1D(6)
>>> h = qu.heisenberg_hamiltonian(g, sparse=False)
>>> tc.backend.eigh(h)[0][:10]
array([-11.2111025,  -8.4721365,  -8.472136 ,  -8.472136 ,  -6.       ,
        -5.123106 ,  -5.123106 ,  -5.1231055,  -5.1231055,  -5.1231055],
    dtype=float32)
Parameters:
  • g (Graph) – input circuit graph

  • hzz (float) – zz coupling, default is 1.0

  • hxx (float) – xx coupling, default is 1.0

  • hyy (float) – yy coupling, default is 1.0

  • hz (float) – External field on z direction, default is 0.0

  • hx (float) – External field on x direction, default is 0.0

  • hy (float) – External field on y direction, default is 0.0

  • sparse (bool, defalts True) – Whether to return sparse Hamiltonian operator, default is True.

  • numpy (bool, defaults False,) – whether return the matrix in numpy or tensorflow form

Returns:

Hamiltonian measurements

Return type:

Tensor

tensorcircuit.quantum.identity(space: Sequence[int], dtype: Any = None) QuOperator[source]

Construct a ‘QuOperator’ representing the identity on a given space. Internally, this is done by constructing ‘CopyNode’s for each edge, with dimension according to ‘space’.

Example:

>>> E = qu.identity((2, 3, 4))
>>> float(E.trace().eval())
24.0
>>> tensor = np.random.rand(2, 2)
>>> psi = qu.QuVector.from_tensor(tensor)
>>> E = qu.identity((2, 2))
>>> psi.eval()
array([[0.03964233, 0.99298281],
       [0.38564989, 0.00950596]])
>>> (E @ psi).eval()
array([[0.03964233, 0.99298281],
       [0.38564989, 0.00950596]])
>>>
>>> (psi.adjoint() @ E @ psi).eval()
array(1.13640257)
>>> psi.norm().eval()
array(1.13640257)
Parameters:
  • space (Sequence[int]) – A sequence of integers for the dimensions of the tensor product factors of the space (the edges in the tensor network).

  • dtype (Any type) – The data type by np.* (for conversion to dense). defaults None to tc dtype.

Returns:

The desired identity operator.

Return type:

QuOperator

tensorcircuit.quantum.log_negativity(rho: Any, transposed_sites: List[int], base: str = 'e', dim: int | None = None) Any[source]

Compute the logarithmic negativity of rho, i.e. the log of \(\lVert\rho^{T_A}\rVert_1\).

Parameters:
  • rho (Tensor) – density matrix of the bipartite system

  • transposed_sites (List[int]) – sites to transpose when forming the partial transpose

  • base (str, optional) – whether use 2 based log or e based log, defaults to “e”

  • dim (int) – dimension of qudit system

Returns:

the logarithmic negativity

Return type:

Tensor

tensorcircuit.quantum.measurement_counts(state: Any, counts: int | None = 8192, format: str = 'count_vector', is_prob: bool = False, random_generator: Any | None = None, status: Any | None = None, jittable: bool = False, dim: int | None = None) Any[source]

Simulate the measuring of each qubit of p in the computational basis, thus producing output like that of qiskit.

Six formats of measurement counts results:

“sample_int”: # np.array([0, 0])

“sample_bin”: # [np.array([1, 0]), np.array([1, 0])]

“count_vector”: # np.array([2, 0, 0, 0])

“count_tuple”: # (np.array([0]), np.array([2]))

“count_dict_bin”: # {“00”: 2, “01”: 0, “10”: 0, “11”: 0} / for cases din [10, 36], “10” -> “A”, …, “35” -> “Z”

“count_dict_int”: # {0: 2, 1: 0, 2: 0, 3: 0}

Example:

>>> n = 4
>>> w = tc.backend.ones([2**n])
>>> tc.quantum.measurement_results(w, counts=3, format="sample_bin", jittable=True)
array([[0, 0, 1, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 1]])
>>> tc.quantum.measurement_results(w, counts=3, format="sample_int", jittable=True)
array([ 7, 15, 11])
>>> tc.quantum.measurement_results(w, counts=3, format="count_vector", jittable=True)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1])
>>> tc.quantum.measurement_results(w, counts=3, format="count_tuple")
(array([1, 2, 8]), array([1, 1, 1]))
>>> tc.quantum.measurement_results(w, counts=3, format="count_dict_bin")
{'0001': 1, '0011': 1, '1101': 1}
>>> tc.quantum.measurement_results(w, counts=3, format="count_dict_int")
{3: 1, 6: 2}
Parameters:
  • state (Tensor) – The quantum state, assumed to be normalized, as either a ket or density operator.

  • counts (int) – The number of counts to perform.

  • shots (int) – alias for the argument counts

  • format (str) – defaults to be “direct”, see supported format above

  • format – alias for the argument format

  • is_prob (bool) – if True, the state is directly regarded as a probability list, defaults to be False

  • random_generator (Optional[Any]) – random_generator, defaults to None

  • status (Optional[Tensor]) – external randomness given by tensor uniformly from [0, 1], if set, can overwrite random_generator

  • jittable (bool) – if True, jax backend try using a jittable count, defaults to False

Returns:

The counts for each bit string measured.

Return type:

Tuple[]

tensorcircuit.quantum.measurement_results(state: Any, counts: int | None = 8192, format: str = 'count_vector', is_prob: bool = False, random_generator: Any | None = None, status: Any | None = None, jittable: bool = False, dim: int | None = None) Any

Simulate the measuring of each qubit of p in the computational basis, thus producing output like that of qiskit.

Six formats of measurement counts results:

“sample_int”: # np.array([0, 0])

“sample_bin”: # [np.array([1, 0]), np.array([1, 0])]

“count_vector”: # np.array([2, 0, 0, 0])

“count_tuple”: # (np.array([0]), np.array([2]))

“count_dict_bin”: # {“00”: 2, “01”: 0, “10”: 0, “11”: 0} / for cases din [10, 36], “10” -> “A”, …, “35” -> “Z”

“count_dict_int”: # {0: 2, 1: 0, 2: 0, 3: 0}

Example:

>>> n = 4
>>> w = tc.backend.ones([2**n])
>>> tc.quantum.measurement_results(w, counts=3, format="sample_bin", jittable=True)
array([[0, 0, 1, 0],
    [0, 1, 1, 0],
    [0, 1, 1, 1]])
>>> tc.quantum.measurement_results(w, counts=3, format="sample_int", jittable=True)
array([ 7, 15, 11])
>>> tc.quantum.measurement_results(w, counts=3, format="count_vector", jittable=True)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1])
>>> tc.quantum.measurement_results(w, counts=3, format="count_tuple")
(array([1, 2, 8]), array([1, 1, 1]))
>>> tc.quantum.measurement_results(w, counts=3, format="count_dict_bin")
{'0001': 1, '0011': 1, '1101': 1}
>>> tc.quantum.measurement_results(w, counts=3, format="count_dict_int")
{3: 1, 6: 2}
Parameters:
  • state (Tensor) – The quantum state, assumed to be normalized, as either a ket or density operator.

  • counts (int) – The number of counts to perform.

  • shots (int) – alias for the argument counts

  • format (str) – defaults to be “direct”, see supported format above

  • format – alias for the argument format

  • is_prob (bool) – if True, the state is directly regarded as a probability list, defaults to be False

  • random_generator (Optional[Any]) – random_generator, defaults to None

  • status (Optional[Tensor]) – external randomness given by tensor uniformly from [0, 1], if set, can overwrite random_generator

  • jittable (bool) – if True, jax backend try using a jittable count, defaults to False

Returns:

The counts for each bit string measured.

Return type:

Tuple[]

tensorcircuit.quantum.mutual_information(s: Any, cut: int | List[int] | Tuple[int, ...] | None = None, dim: int | None = None, *, subsystem_to_keep: Sequence[int] | None = None, subsystems_to_trace_out: Sequence[int] | None = None) Any[source]

Mutual information between the two sides of the bipartition described by cut.

The traced-out subsystem can be specified via the legacy cut argument (int = list(range(cut)) i.e. [0, cut); or an explicit site list) or, preferably, via exactly one of subsystem_to_keep / subsystems_to_trace_out. See reduced_density_matrix() for the full resolution semantics; if both cut and a new argument are given, the new argument wins and cut is ignored (with a UserWarning).

Parameters:
  • s (Tensor) – The density matrix in form of Tensor.

  • cut (Union[int, List[int], Tuple[int, ...], None]) – legacy trace-out specification; prefer the dual arguments below.

  • dim (Optional[int]) – dimension of qudit system, defaults to 2.

  • subsystem_to_keep (Optional[Sequence[int]]) – sites to keep (all others form the other subsystem). Mutually exclusive with subsystems_to_trace_out.

  • subsystems_to_trace_out (Optional[Sequence[int]]) – sites to trace out (defines subsystem A).

Returns:

The mutual information between AB subsystem described by cut.

Return type:

Tensor

tensorcircuit.quantum.onehot_d_tensor(_k: int | Any, d: int = 2) Any[source]

Construct a one-hot vector (or matrix) of local dimension d.

Parameters:
  • _k (int or Tensor) – index or indices to set as 1. Can be an int or a backend Tensor.

  • d (int, optional) – local dimension (number of categories), defaults to 2

Returns:

one-hot encoded vector (shape [d]) or matrix (shape [len(_k), d])

Return type:

Tensor

tensorcircuit.quantum.op2tensor(fn: Callable[[...], Any], op_argnums: int | Sequence[int] = 0) Callable[[...], Any][source]
tensorcircuit.quantum.partial_transpose(rho: Any, transposed_sites: List[int], dim: int | None = None) Any[source]

Compute the partial transpose of a density matrix on the given sites.

Parameters:
  • rho (Tensor) – density matrix

  • transposed_sites (List[int]) – sites int list to be transposed

  • dim (int) – dimension of qudit system

Returns:

the partially transposed density matrix

Return type:

Tensor

tensorcircuit.quantum.ps2coo_core(idx_x: Any, idx_y: Any, idx_z: Any, weight: Any, nqubits: int) Tuple[Any, Any][source]
tensorcircuit.quantum.ps2xyz(ps: List[int]) Dict[str, List[int]][source]

pauli string list to xyz dict

# ps2xyz([1, 2, 2, 0]) = {“x”: [0], “y”: [1, 2], “z”: []}

Parameters:

ps (List[int]) – Pauli string as a list of ints (0=I, 1=X, 2=Y, 3=Z) per qubit

Returns:

dict with keys "x"/"y"/"z" listing the qubit indices where each Pauli acts

Return type:

Dict[str, List[int]]

tensorcircuit.quantum.qop2quimb(qop: QuOperator) Any[source]

Convert QuOperator to MPO or MPS in Quimb package.

Requirements: QuOperator must represent valid MPS/MPO structure: - Linear chain topology with open boundaries only - MPS: no input edges, consistent virtual bonds between adjacent tensors - MPO: equal input/output edges, rank-4 tensors - Edge connectivity: each internal node connected to exactly 2 neighbors - Cyclic boundary conditions NOT supported

Parameters:

qop (QuOperator) – MPO in the form of QuOperator

Returns:

MPO in the form of Quimb package

Return type:

quimb.tensor.tensor_gen.MatrixProductOperator

tensorcircuit.quantum.qop2tenpy(qop: QuOperator) Any[source]

Convert TensorCircuit QuOperator to MPO or MPS from TeNPy.

Requirements: QuOperator must represent valid MPS/MPO structure: - Linear chain topology with open boundaries only - MPS: no input edges, consistent virtual bonds, rank-3 or 4(with empty input edges) tensors - MPO: equal input/output edges, rank-4 tensors - Cyclic boundary conditions NOT supported

Parameters:

qop (QuOperator) – The corresponding state/operator as a QuOperator.

Returns:

MPO or MPS object from the TeNPy package.

Return type:

Union[tenpy.networks.mpo.MPO, tenpy.networks.mps.MPS]

tensorcircuit.quantum.qop2tn(qop: QuOperator) Any[source]

Convert QuOperator back to MPO or MPS in TensorNetwork package.

Parameters:

qop – MPO or MPS in the form of QuOperator, param in docstring

Returns:

MPO or MPS in the form of TensorNetwork

Return type:

Union[tn.matrixproductstates.MPO, tn.matrixproductstates.MPS]

tensorcircuit.quantum.quantum_constructor(out_edges: Sequence[Edge], in_edges: Sequence[Edge], ref_nodes: Collection[AbstractNode] | None = None, ignore_edges: Collection[Edge] | None = None) QuOperator[source]

Constructs an appropriately specialized QuOperator. If there are no edges, creates a QuScalar. If the are only output (input) edges, creates a QuVector (QuAdjointVector). Otherwise creates a QuOperator.

Example:

def show_attributes(op):
    print(f"op.is_scalar()              -> {op.is_scalar()}")
    print(f"op.is_vector()              -> {op.is_vector()}")
    print(f"op.is_adjoint_vector()      -> {op.is_adjoint_vector()}")
    print(f"len(op.out_edges)   -> {len(op.out_edges)}")
    print(f"len(op.in_edges)    -> {len(op.in_edges)}")
>>> psi_node = tn.Node(np.random.rand(2, 2))
>>>
>>> op = qu.quantum_constructor([psi_node[0]], [psi_node[1]])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> False
op.is_adjoint_vector()  -> False
len(op.out_edges)       -> 1
len(op.in_edges)        -> 1
>>> # psi_node[0] -> op.out_edges[0]
>>> # psi_node[1] -> op.in_edges[0]
>>> op = qu.quantum_constructor([psi_node[0], psi_node[1]], [])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> True
op.is_adjoint_vector()  -> False
len(op.out_edges)       -> 2
len(op.in_edges)        -> 0
>>> # psi_node[0] -> op.out_edges[0]
>>> # psi_node[1] -> op.out_edges[1]
>>> op = qu.quantum_constructor([], [psi_node[0], psi_node[1]])
>>> show_attributes(op)
op.is_scalar()          -> False
op.is_vector()          -> False
op.is_adjoint_vector()  -> True
len(op.out_edges)       -> 0
len(op.in_edges)        -> 2
>>> # psi_node[0] -> op.in_edges[0]
>>> # psi_node[1] -> op.in_edges[1]
Parameters:
  • out_edges (Sequence[Edge]) – A list of output edges.

  • in_edges (Sequence[Edge]) – A list of input edges.

  • ref_nodes (Optional[Collection[AbstractNode]], optional) – Reference nodes for the tensor network (needed if there is a. scalar component).

  • ignore_edges (Optional[Collection[Edge]], optional) – Edges to ignore when checking the dimensionality of the tensor network.

Returns:

The new created QuOperator object.

Return type:

QuOperator

tensorcircuit.quantum.quimb2qop(qb_mpo: Any) QuOperator[source]

Convert MPO in Quimb package to QuOperator.

Parameters:

tn_mpo (quimb.tensor.tensor_gen.*) – MPO in the form of Quimb package

Returns:

MPO in the form of QuOperator

Return type:

QuOperator

tensorcircuit.quantum.reachable(inputs: AbstractNode | Iterable[AbstractNode] | Edge | Iterable[Edge]) List[AbstractNode][source]

Computes all nodes reachable from node or edge.node1 by connected edges.

Parameters:

inputs – A AbstractNode/Edge or collection of AbstractNodes/Edges

Returns:

A list of AbstractNode objects that can be reached from node via connected edges.

Raises:

TypeError – If inputs contains other then Edge or Node.

tensorcircuit.quantum.reduced_density_matrix(state: Any | QuOperator, cut: int | List[int] | Tuple[int, ...] | None = None, p: Any | None = None, normalize: bool = True, dim: int | None = None, *, subsystem_to_keep: Sequence[int] | None = None, subsystems_to_trace_out: Sequence[int] | None = None) Any | QuOperator[source]

Compute the reduced density matrix from the quantum state state.

The subsystem can be specified in either of two equivalent ways:

  • cut (legacy): the indices to trace out. If cut is an int, it indicates [0, cut) (i.e. list(range(cut))) as the traced-out region; if it is a sequence, it is the explicit site list.

  • subsystem_to_keep / subsystems_to_trace_out (preferred): exactly one must be given; the other is inferred as the complement. These are mutually exclusive with each other.

If both cut and one of the new arguments are given, the new argument takes precedence and cut is ignored (a UserWarning is emitted).

Parameters:
  • state (Union[Tensor, QuOperator]) – The quantum state in form of Tensor or QuOperator.

  • cut (Union[int, List[int], Tuple[int, ...], None]) – legacy trace-out specification (int = list(range(cut)), i.e. [0, cut); or an explicit site list). Prefer subsystem_to_keep/subsystems_to_trace_out.

  • p (Optional[Tensor]) – probability decoration, default is None.

  • normalize (bool) – if True, returns a trace 1 density matrix. Otherwise, does not normalize.

  • dim (int) – dimension of qudit system

  • subsystem_to_keep (Optional[Sequence[int]]) – sites to keep (all others are traced out). Mutually exclusive with subsystems_to_trace_out.

  • subsystems_to_trace_out (Optional[Sequence[int]]) – sites to trace out.

Returns:

The reduced density matrix.

Return type:

Union[Tensor, QuOperator]

tensorcircuit.quantum.reduced_wavefunction(state: Any, cut: List[int] | Tuple[int, ...] | None = None, measure: List[int] | None = None, dim: int | None = None, *, subsystem_to_keep: Sequence[int] | None = None, subsystems_to_trace_out: Sequence[int] | None = None) Any[source]

Compute the reduced wavefunction from the quantum state state. The fixed measure result is guaranteed by users, otherwise final normalization may required in the return

The reduced (measured) sites can be specified via the legacy cut argument (an explicit site list) or, preferably, via exactly one of subsystem_to_keep / subsystems_to_trace_out. See reduced_density_matrix() for the resolution semantics; if both cut and a new argument are given, the new argument wins and cut is ignored (with a UserWarning).

Parameters:
  • state (Tensor) – wavefunction of the full system

  • cut (Union[List[int], Tuple[int, ...], None]) – the list of position for qubit to be reduced; prefer the dual arguments below.

  • measure (List[int]) – the fixed results of given qubits in the same shape list as the reduced sites

  • dim (int) – dimension of qudit system

  • subsystem_to_keep (Optional[Sequence[int]]) – sites to keep (all others are reduced). Mutually exclusive with subsystems_to_trace_out.

  • subsystems_to_trace_out (Optional[Sequence[int]]) – sites to reduce (measure out).

Returns:

the (unnormalized) reduced wavefunction on the remaining sites

Return type:

Tensor

tensorcircuit.quantum.renyi_entropy(rho: Any | QuOperator, k: int = 2) Any[source]

Compute the Renyi entropy of order \(k\) by given density matrix.

Parameters:
  • rho (Union[Tensor, QuOperator]) – The density matrix in form of Tensor or QuOperator.

  • k (int, optional) – The order of Renyi entropy, default is 2.

Returns:

The \(k\) th order of Renyi entropy.

Return type:

Tensor

tensorcircuit.quantum.renyi_free_energy(rho: Any | QuOperator, h: Any | QuOperator, beta: float = 1, k: int = 2) Any[source]

Compute the Renyi free energy of the corresponding density matrix and Hamiltonian.

Example:

>>> rho = np.array([[1.0, 0], [0, 0]])
>>> h = np.array([[-1.0, 0], [0, 1]])
>>> qu.renyi_free_energy(rho, h, 0.5)
-1.0
>>> qu.free_energy(rho, h, 0.5)
-0.9999999999979998
Parameters:
  • rho (Union[Tensor, QuOperator]) – The density matrix in form of Tensor or QuOperator.

  • h (Union[Tensor, QuOperator]) – Hamiltonian operator in form of Tensor or QuOperator.

  • beta (float, optional) – Constant for the optimization, default is 1.

  • k (int, optional) – The order of Renyi entropy, default is 2.

Returns:

The \(k\) th order of Renyi entropy.

Return type:

Tensor

tensorcircuit.quantum.sample2all(sample: Any, n: int, format: str = 'count_vector', jittable: bool = False, dim: int | None = None) Any[source]

transform sample_int or sample_bin results to other forms specified by format

Parameters:
  • sample (Tensor) – measurement shots results in sample_int (shape [shots]) or sample_bin (shape [shots, n])

  • n (int) – number of sites

  • format (str, optional) – see tensorcircuit.quantum.measurement_results(), defaults to “count_vector”

  • format – alias for the argument format

  • jittable (bool, optional) – only applicable to count transformation in jax backend, defaults to False

  • dim (Optional[int]) – local dimension (2 for qubit; >2 for qudit), defaults to 2

Returns:

measurement results specified as format

Return type:

Any

tensorcircuit.quantum.sample2count(sample: Any, n: int, jittable: bool = True, dim: int | None = None) Tuple[Any, Any][source]

sample_int to count_tuple (indices, counts), size = d**n

Parameters:
  • sample (Tensor) – linear-index samples, shape [shots]

  • n (int) – number of sites

  • jittable (bool) – whether to return fixed-size outputs (backend dependent)

  • dim (int, optional) – local dimension per site, default 2 (qubit)

Returns:

(unique_indices, counts)

Return type:

Tuple[Tensor, Tensor]

tensorcircuit.quantum.sample_bin2int(sample: Any, n: int, dim: int | None = None) Any[source]

bin sample to int sample

Parameters:
  • sample (Tensor) – in shape [trials, n] of elements (0, 1)

  • n (int) – number of sites

  • dim (int, optional) – local dimension, defaults to 2

Returns:

in shape [trials]

Return type:

Tensor

tensorcircuit.quantum.sample_int2bin(sample: Any, n: int, dim: int | None = None) Any[source]

Convert linear-index samples to per-site digits (base-d).

Parameters:
  • sample (Tensor) – shape [trials], integers in [0, d**n)

  • n (int) – number of sites

  • dim (int, optional) – local dimension, defaults to 2

Returns:

shape [trials, n], entries in [0, d-1]

Return type:

Tensor

tensorcircuit.quantum.spin_by_basis(n: int, m: int, elements: Tuple[int, int] = (1, -1)) Any[source]

Generate all n-bitstrings as an array, each row is a bitstring basis. Return m-th col.

Example:

>>> qu.spin_by_basis(2, 1)
array([ 1, -1,  1, -1])
Parameters:
  • n (int) – length of a bitstring

  • m (int) – m<n,

  • elements (Tuple[int, int], optional) – the binary elements to generate, default is (1, -1).

Returns:

The value for the m-th position in bitstring when going through all bitstring basis.

Return type:

Tensor

tensorcircuit.quantum.stabilizer_renyi_entropy(state: Any, alpha: int = 2, status: Any | None = None, with_std: bool = False) Any | Tuple[Any, Any][source]

Compute the pure-state qubit stabilizer Rényi entropy with FWHT.

This implementation currently supports qubit states only. For an N-qubit pure state |psi> and d=2**N, the Pauli correlators are grouped by x using

f_x[b] = conjugate(psi[b]) * psi[b xor x].

An unnormalized fast Walsh-Hadamard transform of f_x returns all correlators in the x family simultaneously. If status is not provided, all x families are evaluated exactly. If status is a rank-one tensor with values in [0, 1), x=0 is evaluated exactly and each status value samples one nonzero x family uniformly. The latter mode gives an unbiased estimator of the moment before the final logarithm and is convenient for JIT-compiled functions because its randomness is supplied externally. If with_std is true, the sampled family moments are also used to estimate the standard error of the final entropy. This adds only scalar accumulators to the sampling scan and does not store all sampled family moments. More precisely, if s_m is the sample standard deviation of the sampled family moments, the returned error bar is the first-order estimate (d - 1) * s_m / (sqrt(K) * abs(1 - alpha) * log(2) * S) for the entropy estimator, where K is the number of nonzero x samples and S is the estimated moment. Thus it is the estimated standard deviation of the final entropy across repeated Monte Carlo runs, rather than the raw standard deviation of the family moments. A fixed Clifford unitary may be inserted into the state-preparation circuit before obtaining state. Since Clifford unitaries permute the Pauli operators, this does not change the exact entropy, but it can change the sampling variance. For structured states, applying Hadamard gates to selected computational-basis qubits is a simple user-controlled preconditioning option. The choice is state-dependent and is not needed for the exact mode.

Parameters:
  • state (Tensor) – Pure-state qubit wavefunction with shape (2**N,).

  • alpha (int, optional) – Integer Rényi order, currently restricted to alpha >= 2.

  • status (Optional[Tensor]) – Optional external uniform random tensor with shape (number_of_samples,) and values in [0, 1).

  • with_std (bool, optional) – If true, return a tuple containing the entropy and an estimated standard error. The standard error is zero in exact mode; sampled mode requires at least two status values.

Returns:

The stabilizer Rényi entropy M_alpha. If with_std is true, return (entropy, standard_error).

Return type:

Union[Tensor, Tuple[Tensor, Tensor]]

tensorcircuit.quantum.taylorlnm(x: Any, k: int) Any[source]

Taylor expansion of \(ln(x+1)\).

Parameters:
  • x (Tensor) – The density matrix in form of Tensor.

  • k (int, optional) – The \(k\) th order, default is 2.

Returns:

The \(k\) th order of Taylor expansion of \(ln(x+1)\).

Return type:

Tensor

tensorcircuit.quantum.tenpy2qop(tenpy_obj: Any) QuOperator[source]

Converts a TeNPy MPO or MPS to a TensorCircuit QuOperator. This definitive version correctly handles axis ordering and boundary conditions to be compatible with eval_matrix.

Parameters:

tenpy_obj (Union[tenpy.networks.mpo.MPO, tenpy.networks.mps.MPS]) – A MPO or MPS object from the TeNPy package.

Returns:

The corresponding state or operator as a QuOperator.

Return type:

QuOperator

tensorcircuit.quantum.tn2qop(tn_obj: Any) QuOperator[source]

Convert MPO in TensorNetwork package to QuOperator.

Parameters:

tn_mpo (tn.matrixproductstates.mpo.*) – MPO in the form of TensorNetwork package

Returns:

MPO in the form of QuOperator

Return type:

QuOperator

tensorcircuit.quantum.trace_distance(rho: Any, rho0: Any, eps: float = 1e-12) Any[source]

Compute the trace distance between two density matrix rho and rho0.

Parameters:
  • rho (Tensor) – The density matrix in form of Tensor.

  • rho0 (Tensor) – The density matrix in form of Tensor.

  • eps (float, optional) – Epsilon, defaults to 1e-12

Returns:

The trace distance between two density matrix rho and rho2.

Return type:

Tensor

tensorcircuit.quantum.trace_product(*o: Any | QuOperator) Any[source]

Compute the trace of several inputs o as tensor or QuOperator.

\[\operatorname{Tr}(\prod_i O_i)\]
Example:

>>> o = np.ones([2, 2])
>>> h = np.eye(2)
>>> qu.trace_product(o, h)
2.0
>>> oq = qu.QuOperator.from_tensor(o)
>>> hq = qu.QuOperator.from_tensor(h)
>>> qu.trace_product(oq, hq)
array([[2.]])
>>> qu.trace_product(oq, h)
array([[2.]])
>>> qu.trace_product(o, hq)
array([[2.]])
Returns:

The trace of several inputs.

Return type:

Tensor

tensorcircuit.quantum.truncated_free_energy(rho: Any, h: Any, beta: float = 1, k: int = 2) Any[source]

Compute the truncated free energy from the given density matrix rho.

Parameters:
  • rho (Tensor) – The density matrix in form of Tensor.

  • h (Tensor) – Hamiltonian operator in form of Tensor.

  • beta (float, optional) – Constant for the optimization, default is 1.

  • k (int, optional) – The \(k\) th order, defaults to 2

Returns:

The \(k\) th order of the truncated free energy.

Return type:

Tensor

tensorcircuit.quantum.u1_enlarge(s: Any, n: int, m: int) Any[source]

Enlarge a state s in the subspace with m down spins in n sites to the full Hilbert space wavefunction of size 2**n

Parameters:
  • s (Tensor) – input state of size C_n^m

  • n (int) – number of total sites

  • m (int) – number of down spins (1 in 0, 1)

Returns:

enlarged state of size 2**n

Return type:

Tensor

tensorcircuit.quantum.u1_inds(n: int, m: int) Any[source]

Generate all the combination index of m down spins in n sites.

print(u1_inds(5, 1))
# [1, 2, 4, 8, 16]
Parameters:
  • n (int) – number of total sites

  • m (int) – number of down spins (1 in 0, 1)

Returns:

index tensor

Return type:

Tensor

tensorcircuit.quantum.u1_mask(n: int, m: int) Any[source]

Return the 1d array of size 2**n filled with zero, one only in elements corresponding to the m down spins

Parameters:
  • n (int) – number of total sites

  • m (int) – number of down spins (1 in 0, 1)

Returns:

boolean/0-1 mask of length 2**n selecting configurations with m down spins

Return type:

Tensor

tensorcircuit.quantum.u1_project(s: Any, n: int, m: int) Any[source]

Project a state s to the subspace with m down spins in n sites

Parameters:
  • s (Tensor) – input state of size 2**n

  • n (int) – number of total sites

  • m (int) – number of down spins (1 in 0, 1)

Returns:

projected state of size C_n^m

Return type:

Tensor

tensorcircuit.quantum.xyz2ps(xyz: Dict[str, List[int]], n: int | None = None) List[int][source]

xyz dict to pauli string list

Parameters:
  • xyz (Dict[str, List[int]]) – dict with keys "x"/"y"/"z" listing qubit indices for each Pauli

  • n (Optional[int], optional) – total number of qubits, defaults to None (inferred from the max index + 1)

Returns:

Pauli string as a list of ints (0=I, 1=X, 2=Y, 3=Z) per qubit

Return type:

List[int]