常见问题#

如何在 GPU 上运行 TensorCircuit#

这是直接通过 ML 后端完成的。GPU 支持是直接取决于 ML 库是否可以在 GPU 上运行,我们不在 tensorcircuit 中处理这个问题。为这些 ML 包配置与 GPU 兼容的环境是用户的责任。请参考这些 ML 包的安装文档,或直接使用 TensorCircuit 提供的官方 dockerfile。在 GPU 兼容的环境下,我们可以通过后端无关的环境变量 CUDA_VISIBLE_DEVICES 来切换使用 GPU 或 CPU。

When should I use GPU for the quantum simulation?#

In general, for a circuit with qubit count larger than 16 or for circuit simulation with large batch dimension more than 16, GPU simulation will be faster than CPU simulation. That is to say, for very small circuits and the very small batch dimensions of vectorization, GPU may show worse performance than CPU. But one have to carry out detailed benchmarks on the hardware choice, since the performance is determined by the hardware and task details.

什么时候该使用 jit?#

For a function with "tensor in and tensor out", wrapping it with jit will greatly accelerate the evaluation. Since the first time of evaluation takes longer time (staging time), jit is only good for functions which have to be evaluated frequently.

警告

Be caution that jit can be easily misused if the users are not familiar with jit mechanism, which may lead to:

  1. very slow performance due to recompiling/staging for each run,

  2. error when run function with jit,

  3. or wrong results without any warning.

The most possible reasons for each problem are:

  1. function input are not all in the tensor form,

  2. the output shape of all ops in the function may require the knowledge of the input value more than the input shape, or use mixed ops from numpy and ML framework

  3. subtle interplay between random number generation and jit (see 随机数,即时编译,后端无关特性,和他们的相互作用 for the correct solution), respectively.

我应该使用哪个 ML 框架后端?#

由于 Numpy 后端不支持自动微分,如果要评估电路梯度,必须将后端设置为 Numpy 之外的 ML 框架之一。

由于 PyTorch 对矢量化和 jit 的支持非常有限,而我们的包强烈依赖于这些特性,因此不建议使用它。尽管总是可以使用 PyTorch 接口将量子函数包装在另一个后端,例如:py:meth:` 张量电路.interfaces.torch_interface`。

就 TensorFlow 和 Jax 后端之间的选择而言,后端的好坏可能取决于用例,并且需要对两者进行基准测试以可能选择更好的后端。没有一种万能的建议,这就是为什么我们维持我们的软件支持不同的后端的形式。

一些一般的经验法则:

  • 在 CPU 和 GPU 上,对于 jax 后端来说,jitted 函数的运行时间更快。

  • 但在 GPU 上,jax 后端的 jit 时间通常要长得多。

  • 对于混合机器学习任务,TensorFlow 拥有更好的 ML 生态系统和可重用的经典 ML 模型。

  • Jax 具有一些 TensorFlow 所缺乏的内置高级功能,例如自动微分中的检查点和用于分布式计算的 pmap。

  • Jax 对自动处理类型提升的 dtype 非常不敏感,这意味着更容易调试。

  • TensorFlow 可以通过 SavedModel 将 jitted 函数缓存在磁盘上,从而进一步摊销编译时间。

PyTorch 和 Jax 后端的 QuantumLayer 对应的是什么?#

Since PyTorch doesn't have mature vmap and jit support and Jax doesn't have native classical ML layers, we highly recommend TensorFlow as the backend for quantum-classical hybrid machine learning tasks, where QuantumLayer plays an important role. For PyTorch, we can in principle wrap the corresponding quantum function into a PyTorch module, we currently have the built-in support for this wrapper as tc.TorchLayer. In terms of the Jax backend, we highly suggested keeping the functional programming paradigm for such machine learning tasks. Besides, it is worth noting that, jit and vmap are automatically taken care of in QuantumLayer.

我什么时候需要定制 contractor 以及如何定制?#

根据经验,对于量子比特数大于 16 且电路深度大于 8 的电路,自定义收缩可能优于默认的内置贪婪收缩策略。

设置或不设置定制 contractor 是在收缩寻路时间和通过 matmul 实际收缩时间之间进行权衡。

在收缩路径搜索方面,定制 contractor 比默认 contractor 花费的时间要多得多。并且通过它找到的路径比真正的收缩找到的路径花费更少的时间和空间。

如果电路仿真时间是整个工作流程的瓶颈,总是可以尝试定制 contractor,看看是否有一些性能改进。

我们建议使用 cotengra library 来设置 contractor,因为有很多有趣的超参数需要调整,我们可以实现更好的收缩路径搜索时间和真实张量网络收缩时间之间的权衡。

"“另外值得注意的是,对于我们通常使用的 jitted 函数,收缩路径搜索只在函数第一次运行时调用,这进一步摊销了时间,有利于使用高度定制的 contractor。

关于如何设置 contractor,请参阅 设置 contractor

对于 Pauli 字符串,有没有比 expectation 更简单的 API?#

假设我们要为六量子位系统测量 \(\langle X_0Z_1Y_2Z_4 \rangle\) ,一般的 expectation API 可能看起来很麻烦。所以可以尝试以下选项之一 :

  • c.expectation_ps(x=[0], y=[2], z=[1, 4])

  • tc.templates.measurements.parameterized_measurements(c, np.array([1, 3, 2, 0, 3, 0]), onehot=True)

我可以根据线路中的经典测量结果来决定后续的量子门操作吗?#

尝试以下方法:(方法甚至完全可以即时编译!)

c = tc.Circuit(2)
c.H(0)
r = c.cond_measurement(0)
c.conditional_gate(r, [tc.gates.i(), tc.gates.x()], 1)

cond_measurement 将根据 z 基础上的测量结果返回 0 或 1,并且 conditional_gate 在电路上应用 gate_list[r]。

How to understand the difference between different measurement methods for Circuit?#

  • tensorcircuit.circuit.Circuit.measure() : used at the end of the circuit execution, return bitstring based on quantum amplitude probability (can also with the probability), the circuit and the output state are unaffected (no collapse). The jittable version is measure_jit.

  • tensorcircuit.circuit.Circuit.cond_measure(): also with alias cond_measurement, usually used in the middle of the circuit execution. Apply a POVM on z basis on the given qubit, the state is collapsed and nomarlized based on the measurement projection. The method returns an integer Tensor indicating the measurement result 0 or 1 based on the quantum amplitude probability.

  • tensorcircuit.circuit.Circuit.post_select(): also with alia mid_measurement, usually used in the middle of the circuit execution. The measurement result is fixed as given from keep arg of this method. The state is collapsed but unnormalized based on the given measurement projection.

Please refer to the following demos:

c = tc.Circuit(2)
c.H(0)
c.H(1)
print(c.measure(0, 1))
# ('01', -1.0)
print(c.measure(0, with_prob=True))
# ('0', (0.4999999657714588+0j))
print(c.state()) # unaffected
# [0.49999998+0.j 0.49999998+0.j 0.49999998+0.j 0.49999998+0.j]

c = tc.Circuit(2)
c.H(0)
c.H(1)
print(c.cond_measure(0))  # measure the first qubit return +z
# 0
print(c.state())  # collapsed and normalized
# [0.70710678+0.j 0.70710678+0.j 0.        +0.j 0.        +0.j]

c = tc.Circuit(2)
c.H(0)
c.H(1)
print(c.post_select(0, keep=1))  # measure the first qubit and it is guranteed to return -z
# 1
print(c.state())  # collapsed but unnormalized
# [0.        +0.j 0.        +0.j 0.49999998+0.j 0.49999998+0.j]

How to understand difference between tc.array_to_tensor and tc.backend.convert_to_tensor?#

tc.array_to_tensor convert array to tensor as well as automatically cast the type to the default dtype of TensorCircuit, i.e. tc.dtypestr and it also support to specify dtype as tc.array_to_tensor( , dtype="complex128"). Instead, tc.backend.convert_to_tensor keeps the dtype of the input array, and to cast it as complex dtype, we have to explicitly call tc.backend.cast after conversion. Besides, tc.array_to_tensor also accepts multiple inputs as a_tensor, b_tensor = tc.array_to_tensor(a_array, b_array).

How to arrange the circuit gate placement in the visualization from c.tex()?#

Try lcompress=True or rcompress=True option in tensorcircuit.circuit.Circuit.tex() API to make the circuit align from the left or from the right.

Or try c.unitary(0, unitary=tc.backend.eye(2), name="invisible") to add placeholder on the circuit which is invisible for circuit visualization.

How to get the entanglement entropy from the circuit output?#

Try the following:

c = tc.Circuit(4)
# omit circuit construction

rho = tc.quantum.reduced_density_matrix(s, cut=[0, 1, 2])
# get the redueced density matrix, where cut list is the index to be traced out

rho.shape
# (2, 2)

ee = tc.quantum.entropy(rho)
# get the entanglement entropy

renyi_ee = tc.quantum.renyi_entropy(rho, k=2)
# get the k-th order renyi entropy