高级用法#
MPS 模拟器#
施工中
Very simple, we provide the same set of API for MPSCircuit
as Circuit
,
the only new line is to set the bond dimension for the new simulator.
c = tc.MPSCircuit(n)
c.set_split_rules({"max_singular_values": 50})
The larger bond dimension we set, the better approximation ratio (of course the more computational cost we pay)
分解双量子比特门#
应用在电路上的双量子比特门可以通过 SVD 进行分解,这可以进一步提高收缩路径查找的最优性。
split 配置可以在电路级或门级设置。
split_conf = {
"max_singular_values": 2, # how many singular values are kept
"fixed_choice": 1, # 1 for normal one, 2 for swapped one
}
c = tc.Circuit(nwires, split=split_conf)
# or
c.exp1(
i,
(i + 1) % nwires,
theta=paramc[2 * j, i],
unitary=tc.gates._zz_matrix,
split=split_conf
)
请注意 max_singular_values
必须被指定明以使整个过程成为静态的,因此是可即时编译的。
即时编译函的保存/加载#
要重新使用可即时编译函数,我们可以通过 TensorFlow SavedModel. 的帮助将其保存在磁盘上。也就是说,只有 TensorFlow 后端的可即时编译量子函数才能保存在磁盘上。
对于 jax-backend 量子函数,可以先通过 jax 实验支持将它们转换为 tf-backend 函数: jax2tf。
我们将 tf-backend SavedModel 包装为非常易于使用的函数 tensorcircuit.keras.save_func()
和 tensorcircuit.keras.load_func()
。
参数化测量#
对于 tc.Circuit
上的普通测量 API, 例如 c = tc.Circuit(n=3), 如果我们要评估期望 \(<Z_1Z_2>\), 我们需要调用API为 c.expectation((tc.gates.z(), [1]), (tc.gates.z(), [2]))
。
在某些情况下,我们可能希望以张量形式告诉软件要测量什么。例如,如果我们想获得上述期望,我们可以使用以下 API : tensorcircuit.templates.measurements.parameterized_measurements()
。
c = tc.Circuit(3)
z1z2 = tc.templates.measurements.parameterized_measurements(c, tc.array_to_tensor([0, 3, 3, 0]), onehot=True) # 1
此 API 对应于测量 \(I_0Z_1Z_2I_3\), 其中 0、1、2、3 分别用于 I、X、Y、Z 局部运算符。
稀疏矩阵#
我们只支持 COO 格式的稀疏矩阵,因为大多数后端只支持这种格式,下面列出了一些常用的稀疏矩阵后端方法:
def sparse_test():
m = tc.backend.coo_sparse_matrix(indices=np.array([[0, 1],[1, 0]]), values=np.array([1.0, 1.0]), shape=[2, 2])
n = tc.backend.convert_to_tensor(np.array([[1.0], [0.0]]))
print("is sparse: ", tc.backend.is_sparse(m), tc.backend.is_sparse(n))
print("sparse matmul: ", tc.backend.sparse_dense_matmul(m, n))
for K in ["tensorflow", "jax", "numpy"]:
with tc.runtime_backend(K):
print("using backend: ", K)
sparse_test()
稀疏矩阵对于评估电路上的哈密顿期望特别有用,其中稀疏矩阵表示在空间和时间之间具有良好的效率。请参阅 tensorcircuit.templates.measurements.sparse_expectation()
了解更多详细信息。
对于在张量电路中评估哈密顿期望的不同表示,请参阅 VQE on 1D TFIM with Different Hamiltonian Representation 。
随机数,即时编译,后端无关特性,和他们的相互作用#
import tensorcircuit as tc
K = tc.set_backend("tensorflow")
K.set_random_state(42)
@K.jit
def r():
return K.implicit_randn()
print(r(), r()) # different, correct
import tensorcircuit as tc
K = tc.set_backend("jax")
K.set_random_state(42)
@K.jit
def r():
return K.implicit_randn()
print(r(), r()) # the same, wrong
import tensorcircuit as tc
import jax
K = tc.set_backend("jax")
key = K.set_random_state(42)
@K.jit
def r(key):
K.set_random_state(key)
return K.implicit_randn()
key1, key2 = K.random_split(key)
print(r(key1), r(key2)) # different, correct
因此,一个与后端无关并且统一可即时编译的随机基础设施可以表述为
import tensorcircuit as tc
import jax
K = tc.set_backend("tensorflow")
def ba_key(key):
if tc.backend.name == "tensorflow":
return None
if tc.backend.name == "jax":
return jax.random.PRNGKey(key)
raise ValueError("unsupported backend %s"%tc.backend.name)
@K.jit
def r(key=None):
if key is not None:
K.set_random_state(key)
return K.implicit_randn()
key = ba_key(42)
key1, key2 = K.random_split(key)
print(r(key1), r(key2))
实现这一目标的更简洁的方法如下:
key = K.get_random_state(42)
@K.jit
def r(key):
K.set_random_state(key)
return K.implicit_randn()
key1, key2 = K.random_split(key)
print(r(key1), r(key2))
值得注意的是,由于 Circuit.unitary_kraus
和 Circuit.general_kraus
调用 implicit_rand*
API,这些 API 的正确用法与上面相同。
有人可能想知道为什么以如此复杂的方式处理随机数,请参阅 Jax 设计说明 提示。
If vmap is also involved apart from jit, I currently find no way to maintain the backend agnosticity as TensorFlow seems to have no support of vmap over random keys (ping me on GitHub if you think you have a way to do this). I strongly recommend the users using Jax backend in the vmap+random setup.