举例来说,我们有一个州有 N 个站点。这些位点中的每一个都可以容纳 0 或 1(其中没有粒子或有粒子)。
例如,对于 N = 3,可能的状态为 |0,0,0>; |1,0,0>; |0,1,0>; |0,0,1>; |1,1,0>; |1,0,1>; |0,1,1>; |1,1,1>
由于与这个问题无关的原因,这些是物理学中粒子状态的表示。更具体地说,这些是无旋费米子的排列。因此,它们是通过在单个状态之间进行张量积来构造的。 例如
|0,1,0> = |0> ⊗ |1> ⊗ |0> (2 号位点有 1 个费米子。1 号位点和 3 号位点为空)
其中每个状态都可以在其自己的空间中明确表示为向量。
|0> = (1,0)(费米子不存在于该 |k> 状态)这也称为真空状态
|1> = (0,1)(费米子存在于该 |k> 状态)
这允许我们进行数值乘积,输出将是最终状态向量,其维度为 2^(N)
所以:
|0,1,0> = |0> ⊗ |1> ⊗ |0> = (1,0) ⊗ (0,1) ⊗ (1,0) = (0, 0, 1, 0, 0, 0, 0, 0) 作为向量
或
|0,1,1> = |0> ⊗ |1> ⊗ |1> = (1,0) ⊗ (0,1) ⊗ (0,1) = (0, 0, 0, 0, 0, 0, 1, 0) 作为向量
问题是对于大量站点来说,计算所有这些张量乘积可能非常耗时。但值得注意的是,无论状态如何,最终的显式 Vector 都将是稀疏的。它在某个位置总是有一个“1”,其余的将保证为零。
我现在的问题是,是否有一个分析表达式可以提前知道唯一的“1”将落在哪里,以便我可以避免做产品?
值得注意的一件有趣的事情是,通过采用上面列举的 8 个状态,对于每个状态,当我们对组合进行排列时,“1”只是在向量中向下移动 1 个索引。而且顺序非常明显。我们首先将“1”元素沿 N 个位置移动。然后我们将第一个元素保留为 0,并将 1 沿着抽象状态的剩余尾部移动。我们重复这样做,直到达到我们的状态。
所以这里我们的 8 个向量形式的枚举状态是有序的:
(1, 0, 0, 0, 0, 0, 0, 0) = |0,0,0>
(0, 1, 0, 0, 0, 0, 0, 0) = |1,0,0>
(0, 0, 1, 0, 0, 0, 0, 0) = |0,1,0>
(0, 0, 0, 1, 0, 0, 0, 0) = |1,1,0>
(0, 0, 0, 0, 1, 0, 0, 0) = |0,0,1>
(0, 0, 0, 0, 0, 1, 0, 0) = |1,0,1>
(0, 0, 0, 0, 0, 0, 1, 0) = |0,1,1>
(0, 0, 0, 0, 0, 0, 0, 1) = |1,1,1>
看待这个问题的一种方法是,这条规则需要多少次排列才能实现我们的规则?如果我们知道这一点,我们就知道唯一的“1”元素将具有索引=这个排列数
这对于 N=3 个站点来说很容易做到。但对于 14 个粒子,这是用肉眼无法做到的。
感谢所有评论者,特别是@Bergi 启发的答案。
不幸的是,我不确定我是否完全同意,因为例如在 10010 -> 10010000 等状态下添加 0 将表示更大的二进制数(更大的索引),但在 1⊗0 和 1⊗0⊗0 之间进行显式张量积⊗0 不改变索引
再次,其中 1 是向量 (0,1),0 是 (1,0)。虽然它确实改变了整体维度。
话虽这么说,我是这样处理的。我将输入字符串中的第一个状态 0 或 1 对应于它自己的向量。如果状态为 0,则最终索引 = 0,如果 1 索引 = 1。我在字符串上向右移动,如果下一个条目是 0 状态,我只需将维度加倍并保持索引不变。但是,如果下一个状态是 1,我会将维度加倍并将其添加到当前索引。这表示如果将向量与 (0,1) 进行张量乘积,则会进行移位。代码如下:
create_fermions 创建 f_state 结构,它只是二进制字符串(这些是整数的原因是因为它们稍后将用于直接对角化。实际上它们应该是双精度数,但现在这不是问题)。该功能是为了方便用户输入状态
create_explicit_fermion 获取前一个函数的输出,并使用上面描述的技术返回指向显式向量/数组表示的指针。 “1”元素的索引似乎位于正确的位置。
%%cython
cimport cython
from libc.stdlib cimport malloc, free
from cython cimport sizeof
#import numpy as np
#cimport numpy as np
ctypedef struct f_state:
int* state
int size
cdef void free_fermions(f_state fstate) nogil:
free(fstate.state)
cdef f_state create_fermions(str state, int space_size):
cdef int* state_array = <int*>malloc(space_size*sizeof(int))
if state_array is NULL:
raise MemoryError("Failed to allocate memory for state_array")
for i in range(space_size):
if state[i] not in ('0', '1'):
raise ValueError("spinless fermion states can only have 1 occupation or none 0")
state_array[i] = <int>state[i]-48 #minus 48 because of ascii encoding from str to int. 0 is 48 in ascii. 1 is 49
cdef f_state fstate
fstate.state = state_array
fstate.size = space_size
return fstate
cdef int* create_explicit_fermions(f_state in_state):
#start by allocating the vector
cdef int total_size = 2**in_state.size
#malloc this to mem
#....to be completed
cdef int tmp_dimension
cdef int index
if in_state.state[0] == 0:
index = 0
elif in_state.state[0] == 1:
index = 1
if (in_state.size > 1):
for i in range(in_state.size):
tmp_dimension = 2**(i+1)
if (in_state.state[i+1] == 0):
index = index
elif (in_state.state[i+1] == 1):
index = index + tmp_dimension
cdef int* result = <int*>malloc(total_size*sizeof(int))
for i in range(total_size):
result[i] = 0
result[index] = 1
return result
#test unit 2
cdef str fermions = "001"
cdef int fsize = 3
cdef f_state fermion_state = create_fermions(fermions, fsize)
for i in range(fsize):
print(fermion_state.state[i])
print("\nnow the explicit vector\n")
cdef int* fermion_vector = create_explicit_fermions(fermion_state)
for i in range(2**fsize):
print(fermion_vector[i])
free_fermions(fermion_state)
free(fermion_vector)
以下测试单元给出
the state in diract notation
0
0
1
the state in an explicit Fock space vector
0
0
0
0
1
0
0
0
如果您手动计算张量积,这是正确的结果
更复杂的示例:
费米子=“010010” f 大小 = 6
给予
the state in diract notation
0
1
0
0
1
0
the state in an explicit Fock space vector
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
在索引 18
感谢这些,我现在可以计算创建-消灭运算符的完整矩阵
@Bergi 如果有办法按照您的建议或更有效地做到这一点,请随时提供代码。谢谢你的帮助