tensorcircuit.quantum

Quantum state and operator class backend by tensornetwork

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. Currently requires tensorflow installed

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

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

Generate sparse tensor from Pauli string sum. Currently requires tensorflow installed

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

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. Currently requires tensorflow installed.

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]

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() QuOperator

The norm of the operator. This is the 2-norm (also known as the Frobenius or Hilbert-Schmidt norm).

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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() QuOperator

The trace of the operator.

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() QuOperator[source]

The norm of the operator. This is the 2-norm (also known as the Frobenius or Hilbert-Schmidt norm).

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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() QuOperator[source]

The trace of the operator.

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() QuOperator

The norm of the operator. This is the 2-norm (also known as the Frobenius or Hilbert-Schmidt norm).

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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() QuOperator

The trace of the operator.

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() QuOperator

The norm of the operator. This is the 2-norm (also known as the Frobenius or Hilbert-Schmidt norm).

property out_space: List[int]
partial_trace(subsystems_to_trace_out: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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: Collection[int]) 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.

Parameters:

subsystems_to_trace_out (Collection[int]) – Indices of 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() QuOperator

The trace of the operator.

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 probability for each bitstring is given as a vector results. Results is in the format of “count_vector”

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) – probability vector of shape 2^n

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) – [description]

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

Returns:

[description]

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]) – [description]

  • n (int) – number of qubits

  • dim (int, optional) – [description], defaults to None

Returns:

[description]

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) – [description]

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

Returns:

[description]

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]) – [description]

  • n (int) – number of qubits

  • dim (int, optional) – [description], defaults to None

Returns:

[description]

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_entropy(state: Any, cut: int | List[int]) Any[source]
tensorcircuit.quantum.entanglement_negativity(rho: Any, transposed_sites: List[int], dim: int | None = None) Any[source]

_summary_

Parameters:
  • rho (Tensor) – _description_

  • transposed_sites (List[int]) – _description_

  • dim (int) – dimension of qudit system

Returns:

_description_

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 fidelity scalar between two states rho and rho0.

\[\operatorname{Tr}(\sqrt{\sqrt{rho} rho_0 \sqrt{rho}})\]
Parameters:
  • rho (Tensor) – The density matrix in form of Tensor.

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

Returns:

The sqrtm of a Hermitian matrix a.

Return type:

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. Currently requires tensorflow installed

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 y direction, default is 0.0

  • hy (float) – External field on x 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 = 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]

_summary_

Parameters:
  • rho (Tensor) – _description_

  • transposed_sites (List[int]) – _description_

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

  • dim (int) – dimension of qudit system

Returns:

_description_

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], dim: int | None = None) Any[source]

Mutual information between AB subsystem described by cut.

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

  • cut (Union[int, List[int]]) – The AB subsystem.

  • dim (Tensor) – The diagonal matrix in form of Tensor.

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]

_summary_

Parameters:
  • rho (Tensor) – density matrix

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

  • dim (int) – dimension of qudit system

Returns:

_description_

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]) – _description_

Returns:

_description_

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], p: Any | None = None, normalize: bool = True, dim: int | None = None) Any | QuOperator[source]

Compute the reduced density matrix from the quantum state state.

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

  • cut (Union[int, List[int]]) – the index list that is traced out, if cut is a int, it indicates [0, cut] as the traced out region

  • 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

Returns:

The reduced density matrix.

Return type:

Union[Tensor, QuOperator]

tensorcircuit.quantum.reduced_wavefunction(state: Any, cut: List[int], measure: List[int] | None = None, dim: 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

Parameters:
  • state (Tensor) – _description_

  • cut (List[int]) – the list of position for qubit to be reduced

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

  • dim (int) – dimension of qudit system

Returns:

_description_

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.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 rho2.

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:

_description_

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]]) – _description_

  • n (Optional[int], optional) – _description_, defaults to None

Returns:

_description_

Return type:

List[int]