我想在Julia中实现一个元胞自动机(CA(。尺寸应该换行,这意味着:最左边单元格的左邻是最右边的单元格,依此类推。
一个关键问题是:如何让一个细胞的邻居计算下一代细胞的状态?由于尺寸应该被包装并且 Julia 不允许负索引(如在 Python 中(,我有这个想法:
被视为一维CA,一代是一维数组:
0 0 1 0 0
如果我们创建一个二维数组,其中第一行向右移动,第三行向左移动,如下所示:
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
现在,第一列包含第一个单元格的状态及其邻居等。
我认为这可以很容易地推广到两个和更多的维度。
第一个问题:你认为这是一个好主意,还是一个错误的轨道?
编辑:第一个问题的答案是否定的,第二个问题和代码示例被丢弃。
第二个问题:如果方法基本没问题,请看下面的草图:
编辑:其他方法,这是1D CA的精简版本,使用mod1((获取邻域索引,正如Bogumił Kamiński所建议的那样。
对于任何单元格: - 所有索引的数组 - 所有邻域状态的B数组 - C 状态转换为一个整数 - D 查找下一个状态
function digits2int(digits, base=10)
int = 0
for digit in digits
int = int * base + digit
end
return int
end
gen = [0,0,0,0,0,1,0,0,0,0,0]
rule = [0,1,1,1,1,0,0,0]
function nextgen(gen, rule)
values = [mod1.(x .+ [-1,0,1], size(gen)) for x in 1:length(gen)] # A
values = [gen[value] for value in values] # B
values = [digits2int(value, 2) for value in values] # C
values = [rule[value+1] for value in values] # D
return values
end
for _ in 1:100
global gen
println(gen)
gen = nextgen(gen, rule)
end
下一步应该是将其扩展到二维,现在就尝试...
我通常的做法是使用mod1
函数进行包装索引。
在这种方法中,无论数组a
的维数如何,当您想从位置移动到 deltax
dx
如果x
是数组的第一维,则写入mod1(x+dx, size(a, 1))
就足够了。
下面是一个在 2D 圆环上随机游走的简单示例,计算给定单元格被访问的次数(在这里,我还使用广播在一个表达式中处理所有维度(:
function randomwalk()
a = zeros(Int, 8, 8)
pos = (1,1)
for _ in 1:10^6
# Von Neumann neighborhood
dpos = rand(((1,0), (-1,0), (0,1), (0,-1)))
pos = mod1.(pos .+ dpos, size(a))
a[pos...] += 1
end
a
end
通常,如果 CA 的单元格仅依赖于它们旁边的单元格,则更简单的是将最后一个元素添加到前面,将第一个元素添加到后面,进行模拟,然后"解包"通过再次将第一个和最后一个元素移开,以获得与起始数组长度相同的结果长度。对于一维情况:
const lines = 10
const start = ".........#........."
const rules = [90, 30, 14]
rule2poss(rule) = [rule & (1 << (i - 1)) != 0 for i in 1:8]
cells2bools(cells) = [cells[i] == '#' for i in 1:length(cells)]
bools2cells(bset) = prod([bset[i] ? "#" : "." for i in 1:length(bset)])
function transform(bset, ruleposs)
newbset = map(x->ruleposs[x],
[bset[i + 1] * 4 + bset[i] * 2 + bset[i - 1] + 1
for i in 2:length(bset)-1])
vcat(newbset[end], newbset, newbset[1])
end
const startset = cells2bools(start)
for rul in rules
println("nUsing Rule $rul:")
bset = vcat(startset[end], startset, startset[1]) # wrap ends
rp = rule2poss(rul)
for _ in 1:lines
println(bools2cells(bset[2:end-1])) # unwrap ends
bset = transform(bset, rp)
end
end
只要在模拟中仅对任何给定像元使用相邻像元,这都是正确的。
如果将其扩展到 2D 矩阵,则还将"包装"第一行和最后一行以及第一列和最后一列,依此类推。