cuquantum.cutensornet.experimental.contract_decompose

cuquantum.cutensornet.experimental.contract_decompose(subscripts, *operands, algorithm=None, options=None, optimize=None, stream=None, return_info=False)[源代码]

评估输入操作数上收缩和分解的复合表达式。

该表达式遵循爱因斯坦求和符号进行收缩和分解符号进行分解的组合(如 decompose())。输入表示一个张量网络,该网络将被收缩以形成中间张量,以便进行后续分解操作,根据最终分解方法产生两个或三个输出。该表达式需要显式指定输入和输出张量的模式(不包括 SVD 方法的 S)。中间张量的模式是根据表示输出模式的下标通过使用爱因斯坦求和表达式的隐式形式推断出来的(类似于 numpy.einsum 隐式模式中的处理)。

请参阅注释和示例以进行澄清。

参数
  • subscripts – 模式标签(下标),用于定义收缩和分解操作,以逗号分隔的字符序列表示。表达式中允许使用 Unicode 字符,从而扩展了可以指定的张量网络的大小。

  • algorithm – 指定执行收缩和分解的算法。或者,可以提供一个 dict,其中包含 ContractDecomposeAlgorithm 构造函数的参数。如果未指定,则该值将设置为默认构造的 ContractDecomposeAlgorithm 对象。

  • operands – 张量序列(类 ndarray 对象)。当前支持的类型为 numpy.ndarraycupy.ndarraytorch.Tensor

  • options – 将张量网络的选项指定为 NetworkOptions 对象。或者,也可以提供一个 dict,其中包含 NetworkOptions 构造函数的参数。如果未指定,则该值将设置为默认构造的 NetworkOptions 对象。

  • optimize – 此参数将路径优化的选项指定为 OptimizerOptions 对象。或者,也可以提供一个字典,其中包含 OptimizerOptions 构造函数的参数。如果未指定,则该值将设置为默认构造的 OptimizerOptions 对象。

  • stream – 提供 CUDA 流以用于自动调优操作。可接受的输入包括 cudaStream_t(作为 Python int)、cupy.cuda.Streamtorch.cuda.Stream。如果未提供流,将使用当前流。

  • return_info – 如果为 true,则有关收缩和分解的信息也将作为 :ContractDecomposeInfo 对象返回。

返回

  • 对于 QR 分解(默认),如果 return_infoFalse,则输出张量 Q 和 R(类 ndarray 对象)的类型和设备与输入操作数相同,作为分解的结果返回。如果 return_infoTrue,则将返回输出张量 Q、R 和 ContractDecomposeInfo 对象的三元组,其中包含有关操作的信息。

  • 对于 SVD 分解,如果 return_infoFalse,则返回输出张量 U、S 和 V(类 ndarray 对象)的三元组,其类型与输入操作数相同,作为分解的结果。如果 return_infoTrue,则将返回输出张量 U、S、V 和 ContractDecomposeInfo 对象的四元组,其中包含有关操作的信息。注意,根据 partition 的选择,返回的 S 操作数可能为 None。另请参阅 partition

返回类型

根据 algorithm 中指定的分解设置,返回的结果可能会有所不同

引发

MemoryLimitExceeded – 执行操作所需的内存大于 options.memory_limit

收缩和分解表达式采用了爱因斯坦求和符号进行收缩和 decompose() 中引入的分解符号的组合。subscripts 字符串是下标标签的列表,其中每个标签都引用相应操作数的模式。下标标签由逗号或标识符 -> 分隔。标识符 -> 之前的下标标签被视为输入,之后的下标标签分别被视为输出。SVD 和 QR 分解的下标要求总结如下

  • 对于 SVD 和 QR 分解,下标字符串应包含多个输入和恰好两个输出标签(对于 SVD,S 的模式不是必需的)。

  • 预计两个输出模式标签中存在一个且仅一个相同的模式。

  • 中间张量的模式(将被分解)是根据表示输出模式的下标通过使用爱因斯坦求和表达式的隐式形式推断出来的(类似于 numpy.einsum 隐式模式中的处理)。因此,将输入模式和中间模式组合在一起应产生有效的 numpy.einsum 表达式(经典或广义)。

示例

>>> # equivalent:
>>> # q, r = numpy.linalg.qr(numpy.einsum('ij,jk->ik', a, b))
>>> q, r = contract_decompose('ij,jk->ix,xk', a, b)
>>> # equivalent:
>>> # u, s, v = numpy.linalg.svd(numpy.einsum('ij,jk->ik', a, b), full_matrices=False)
>>> u, s, v = tensor_decompose('ij,jk->ix,xk', a, algorithm={'qr_method':False, 'svd_method': {}})

对于推广到具有多维张量的通用张量网络(abc 均为秩为 4 的张量)。在这种情况下,中间模式 ijabe 是从输出模式 ixebjax 推断出来的

>>> # equivalent:
>>> # t = contract('ijc,cad,dbe->ijabe', a, b, c)
>>> # u, s, v = tensor.decompose('ijabe->ixeb,jax', t, method=SVDMethod())
>>> u, s, v = contract_decompose('ijc,cad,dbe->ixeb,jax', a, b, c, algorithm={'qr_method': False, 'svd_method': {}})

如果 contract 和 decompose 问题相当于量子电路模拟中常见的 三元操作门分裂问题 (详情请参阅 门分裂算法),用户或许可以利用 cutensornetGateSplit() 中的优化内核,方法是将门操作数放在输入操作数的最后一个。在这种情况下,QR 分解有可能被用于加速 contraction 和 SVD 的执行。这可以通过设置 qr_methodsvd_method 来实现,如下所示。

示例

将双量子比特门应用于相邻的 MPS 张量

>>> a, _, b = contract_decompose('ipj,jqk,pqPQ->iPx,xQk', a, b, gate, algorithm={'qr_method':{}, 'svd_method':{}})

广播 (Broadcasting) 通过省略号表示法支持某些情况。可以在输入模式中添加省略号来表示标签中未明确指定的所有模式。在这种情况下,允许在一个输出模式中最多出现一个省略号。如果一个输出模式中出现省略号,则隐式模式将被分配到相应的输出。如果在输出中没有找到省略号,则将对隐式模式求和以构建中间张量。

示例

以下是基于两个秩为 4 的张量 ab 的一些示例

>>> # equivalent:
>>> # out = contract_decompose('ijab,abcd->ijx,xcd', a, b)
>>> out = contract_decompose('ijab,ab...->ijx,x...', a, b)  # intermediate modes being "ijcd"
>>> # equivalent:
>>> # out = contract_decompose('ijab,abcd->ix,xj', a, b)
>>> out = contract_decompose('ijab,ab...->ix,xj', a, b)  # intermediate modes being "ij"
>>> # equivalent:
>>> # out = contract_decompose('ijab,jkab->ix,xj', a, b)
>>> out = contract_decompose('ij...,jk...->ix,xj', a, b)  # intermediate modes being "ij"
>>> # equivalent:
>>> # out = contract_decompose('ijab,jkab->ixab,xj', a, b)
>>> out = contract_decompose('ij...,jk...->ix...,xj', a, b)  # intermediate modes being "ijab"

请注意,由省略号隐式表示的模式数量在所有出现的情况中必须相同。

注意

鼓励用户自行维护库句柄,以减少上下文初始化时间

from cuquantum import cutensornet as cutn
from cuquantum.cutensornet.experimental import contract_decompose

handle = cutn.create()
q, r = contract_decompose(..., options={"handle": handle}, ...)
# ... the same handle can be reused for further calls ...
# when it's done, remember to destroy the handle
cutn.destroy(handle)