def __init__(self, Lx=60, Ly=60, plot=True, frames=1000, boundary={'h': 'periodic', 'v': 'periodic'}, pre_function=None, post_function=None): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) center_x, center_y = Lx / 4, Ly / 2 self.points = [(center_x, center_y)] self.occupied[center_x, center_y] = True self.neighbors = list(map( tuple, np.array(self.lattice.neighbor_of(center_x, center_y)).T )) self.plot = plot self.interval = 1 self.frames = frames self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = []
def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], plot=True, beta=4.): self.plot = plot self.beta = beta self.interval = 1 self.frames = 20000 # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={'h': 'periodic', 'v': 'periodic'} ) randomize(self.lattice) self.triang_standard = tri.Triangulation(self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) # Put the strings to the lattice self.strings = self.create_random_strings(N, size)
def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=1000): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={'h': 'periodic', 'v': 'periodic'}) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) * Ly # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = True self.interval = interval
def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=1000): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary='periodic') self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) * Ly # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = True self.interval = interval
def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=50, plot=True): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary={'h': 'periodic', 'v': 'periodic'}) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = plot self.interval = interval
def __init__(self, Lx=60, Ly=60, plot=True, frames=1000, boundary={ 'h': 'periodic', 'v': 'periodic' }, pre_function=None, post_function=None): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) center_x, center_y = Lx / 4, Ly / 2 self.points = [(center_x, center_y)] self.occupied[center_x, center_y] = True self.neighbors = list( map(tuple, np.array(self.lattice.neighbor_of(center_x, center_y)).T)) self.plot = plot self.interval = 1 self.frames = frames self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = []
class SAW(base): """2次元三角格子上の自己回避ランダムウォーク""" def __init__(self, Lx=40, Ly=40, boundary={ 'h': 'periodic', 'v': 'periodic' }, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta=2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: if string.loop: raise AttributeError("string can't be loop.") self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError( "`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs(s=self.strings[key], index_start=0, index_stop=len( self.strings[key].pos)) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def __update_dict(self, dict, key, value): if dict.has_key(key): dict[key].append(value) else: dict[key] = [value] def dot(self, v, w): """0〜5で表された6つのベクトルの内積を計算する。 v, w (int): ベクトル(0〜5の整数で表す)""" if (w + 6 - v) % 6 == 0: return 1 elif (w + 6 - v) % 6 == 1 or (w + 6 - v) % 6 == 5: return 0.5 elif (w + 6 - v) % 6 == 2 or (w + 6 - v) % 6 == 4: return -0.5 elif (w + 6 - v) % 6 == 3: return -1. def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y X_min, X_max = min(self.lattice_X) - 0.1, max(self.lattice_X) + 0.1 Y_min, Y_max = min(self.lattice_Y) - 0.1, max(self.lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(self.lattice_X, self.lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [ self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines) ] if self.plot_surface: self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.plot_string() def start_animation(self, filename=""): if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) if filename != "": try: ani.save(filename, codec="libx264", bitrate=-1, fps=30) except: print("Can't saved.") else: print("Animation is successfully saved at '%s'." % filename) else: plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y if dist_x > 1.5 * self.lattice.dx or dist_y > 1.5 * self.lattice.dy: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 if self.plot_surface: neighbors = [] weights = [] for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos in bonding_pairs.keys(): neighbors.append(pos) for weight in bonding_pairs.values(): weights.append(weight[0][1]) neighbors = list(np.array(neighbors).T) weights = np.array(weights) weights = weights / np.sum(weights) # print(neighbors) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] # print(X, Y) self.lines[-1].set_data(X, Y) # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット if self.plot_surface: max_obj = len(self.lines) - 1 else: max_obj = len(self.lines) for j in range(i, max_obj): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # update each string for i, s in enumerate(self.strings): if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self, i, s)) ret = self.update_each_string(i) if self.post_function is not None: self.post_func_res.append(self.post_function(self, i, s)) if self.plot or self.save_video: ret = self.plot_string() return ret def update_each_string(self, key): X = self.get_neighbor_xy(key) if not X: raise StopIteration # print(X) s = self.strings[key] # update positions if len(X) == 4: i, r_rev, nx, ny = X s.x, s.y = nx, ny s.insert(0, r_rev) x, y = s.pos_x[0], s.pos_y[0] elif len(X) == 2: i, r = X s.insert(i + 1, r) x, y = s.pos_x[-1], s.pos_y[-1] else: raise RuntimeError( "Something wrong. There should be no intersection part.") self.occupied[x, y] = True # print("== start == (%d, %d)" % (x, y)) # pp.pprint(self.bonding_pairs[key]) for k, bonding_pairs in self.bonding_pairs.items(): if bonding_pairs.has_key((x, y)): del self.bonding_pairs[k][(x, y)] # print("del self.bonding_pairs[%d][(%d, %d)]" % (k, x, y)) # pp.pprint(self.bonding_pairs[key]) index_start = i index_stop = len(s.pos) self.cleanup_bonding_pairs(key=key, index_start=index_start, index_stop=index_stop) value = self.get_bonding_pairs(s=self.strings[key], index_start=index_start, index_stop=index_stop) # pp.pprint(value) # pp.pprint(self.bonding_pairs[key]) for k, v in value.items(): if self.bonding_pairs[key].has_key(k): self.bonding_pairs[key][k] += v else: self.bonding_pairs[key][k] = v # self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs[key]) # print("== end ==") # pp.pprint(self.strings[key].pos) # pp.pprint(self.bonding_pairs[key].keys()) def cleanup_bonding_pairs(self, key, index_start, index_stop): rang = range(index_start, index_stop) for (x, y), l in self.bonding_pairs[key].items(): tmp = [] for i, (bonding_pair, w) in enumerate(l): if not bonding_pair[0] in rang: tmp.append(l[i]) if len(tmp) == 0: del self.bonding_pairs[key][(x, y)] else: self.bonding_pairs[key][(x, y)] = tmp def get_neighbor_xy(self, key): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ if len(self.bonding_pairs[key]) == 0: return False # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] bonding_pairs = [] b = reduce(operator.add, self.bonding_pairs[key].values()) # print(b) for (pair, w) in b: bonding_pairs.append(pair) weights.append(w) weights = np.array(weights) weights = weights / np.sum(weights) # print(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) # print(bonding_pairs[choiced_index]) return bonding_pairs[choiced_index] def get_bonding_pairs(self, s, index_start, index_stop): bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r], nny[r] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r_rev = (r + 3) % 6 if i == 0: w = self.dot(r_rev, s.vec[0]) W = np.exp(self.beta * w) self.__update_dict(bonding_pairs, (nx, ny), [[0, r_rev, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(s.vec[i - 1], r) W = np.exp(self.beta * w) self.__update_dict(bonding_pairs, (nx, ny), [[i, r], W]) return bonding_pairs
def __init__(self, Lx=40, Ly=40, boundary={ 'h': 'periodic', 'v': 'periodic' }, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta=2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: if string.loop: raise AttributeError("string can't be loop.") self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError( "`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs(s=self.strings[key], index_start=0, index_stop=len( self.strings[key].pos)) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close()
def __init__(self, Lx=40, Ly=40, boundary={'h': 'periodic', 'v': 'periodic'}, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta = 2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT( np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary ) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: if string.loop: raise AttributeError("string can't be loop.") self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError("`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], index_start=0, index_stop=len(self.strings[key].pos) ) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close()
class Main(base): def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], plot=True): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={ 'h': 'periodic', 'v': 'periodic' }) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = plot self.interval = 100 def update(self, num=0): # move head part of each strings (if possible) for s in self.strings: X = self.get_next_xy(s.x, s.y, s.vec[0]) if not X: raise StopIteration # update starting position x, y, vec = X rmx, rmy = s.follow((x, y, (vec + 3) % 6)) self.occupied[x, y] = True self.occupied[rmx, rmy] = False ret = self.plot_string() if self.plot: ret = self.plot_string() return ret def get_next_xy(self, x, y, vec): # 曲げ弾性の効果を再現するために,位置関係によって次の点の # 選ばれやすさが異なるようにする nnx, nny = self.lattice.neighbor_of(x, y) vectors = [i for i in range(6) if not self.occupied[nnx[i], nny[i]]] if len(vectors) == 0: print_debug("no neighbors") return False # 確率的に方向を決定 # 先頭ベクトルを0とした時の相対ベクトルごとの選ばれやすさを設定 # weights = [0., 1., 2., 3., 2., 1.] weights = [0., 0., 1., 4., 1., 0.] # weights = [0., 0., 2., 1., 2., 0.] # weights = [0., 0., 0., 1., 0., 0.] # 有効なものだけ取り出す weights = np.array([weights[(i + 6 - vec) % 6] for i in vectors]) # 規格化 weights = weights / np.sum(weights) # vectorsから一つ選択 vector = np.random.choice(vectors, p=weights) # 点の格子座標を返す x, y = nnx[vector], nny[vector] return x, y, vector def create_random_strings(self, N=3, size=[10, 5, 3]): """Create N strings of each size is specified with 'size'. This process is equivalent to self-avoiding walk on triangular lattice. """ strings = [] n = 0 while n < N: # set starting point x = random.randint(0, self.lattice.Lx - 1) y = random.randint(0, self.lattice.Ly - 1) if self.occupied[x, y]: # reset print_debug("(%d, %d) is occupied already. continue." % (x, y)) continue self.occupied[x, y] = True S = size[n] pos = [(x, y, np.random.choice(6))] trial, nmax = 0, 10 double = 0 while len(pos) < S: if trial > nmax: for _x, _y, vec in pos: self.occupied[_x, _y] = False print_debug("All reset") break X = self.get_next_xy(x, y, pos[-1][2]) if not X: if len(pos) == 1: print_debug("len(pos) == 1") double = 0 trial += 1 break else: print_debug("back one step") print_debug(pos) if double == 1: print_debug("two time. back two step") print_debug(pos) oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 print_debug(pos) break oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 print_debug(pos) continue else: double = 0 x, y, vector = X self.occupied[x, y] = True pos.append((x, y, vector)) print_debug("add step normally") print_debug(pos) else: print_debug("Done. Add string") vec = [v[2] for v in pos][1:] strings.append( String(self.lattice, n, pos[0][0], pos[0][1], vec=vec)) n += 1 return strings
def __init__(self, Lx=40, Ly=40, boundary={'h': 'periodic', 'v': 'periodic'}, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta = 2., interval=0, weight_const=0.5, strings=None, pre_function=None, post_function=None): self.lattice = LT( np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary ) ## randomize randomize(self.lattice) ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.triang_standard = tri.Triangulation(self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError("`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos) ) self.bonding_pairs[key] = value self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close()
class SAW(base): """2次元三角格子上の自己回避ランダムウォーク""" def __init__(self, Lx=40, Ly=40, boundary={'h': 'periodic', 'v': 'periodic'}, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta = 2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT( np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary ) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: if string.loop: raise AttributeError("string can't be loop.") self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError("`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], index_start=0, index_stop=len(self.strings[key].pos) ) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def __update_dict(self, dict, key, value): if dict.has_key(key): dict[key].append(value) else: dict[key] = [value] def dot(self, v, w): """0〜5で表された6つのベクトルの内積を計算する。 v, w (int): ベクトル(0〜5の整数で表す)""" if (w + 6 - v) % 6 == 0: return 1 elif (w + 6 - v) % 6 == 1 or (w + 6 - v) % 6 == 5: return 0.5 elif (w + 6 - v) % 6 == 2 or (w + 6 - v) % 6 == 4: return -0.5 elif (w + 6 - v) % 6 == 3: return -1. def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y X_min, X_max = min(self.lattice_X) - 0.1, max(self.lattice_X) + 0.1 Y_min, Y_max = min(self.lattice_Y) - 0.1, max(self.lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(self.lattice_X, self.lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines)] if self.plot_surface: self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.plot_string() def start_animation(self, filename=""): if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) if filename != "": try: ani.save(filename, codec="libx264", bitrate=-1, fps=30) except: print("Can't saved.") else: print("Animation is successfully saved at '%s'." % filename) else: plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y if dist_x > 1.5 * self.lattice.dx or dist_y > 1.5 * self.lattice.dy: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 if self.plot_surface: neighbors = [] weights = [] for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos in bonding_pairs.keys(): neighbors.append(pos) for weight in bonding_pairs.values(): weights.append(weight[0][1]) neighbors = list(np.array(neighbors).T) weights = np.array(weights) weights = weights / np.sum(weights) # print(neighbors) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] # print(X, Y) self.lines[-1].set_data(X, Y) # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット if self.plot_surface: max_obj = len(self.lines) - 1 else: max_obj = len(self.lines) for j in range(i, max_obj): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # update each string for i, s in enumerate(self.strings): if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self, i, s)) ret = self.update_each_string(i) if self.post_function is not None: self.post_func_res.append(self.post_function(self, i, s)) if self.plot or self.save_video: ret = self.plot_string() return ret def update_each_string(self, key): X = self.get_neighbor_xy(key) if not X: raise StopIteration # print(X) s = self.strings[key] # update positions if len(X) == 4: i, r_rev, nx, ny = X s.x, s.y = nx, ny s.insert(0, r_rev) x, y = s.pos_x[0], s.pos_y[0] elif len(X) == 2: i, r = X s.insert(i + 1, r) x, y = s.pos_x[-1], s.pos_y[-1] else: raise RuntimeError("Something wrong. There should be no intersection part.") self.occupied[x, y] = True # print("== start == (%d, %d)" % (x, y)) # pp.pprint(self.bonding_pairs[key]) for k, bonding_pairs in self.bonding_pairs.items(): if bonding_pairs.has_key((x, y)): del self.bonding_pairs[k][(x, y)] # print("del self.bonding_pairs[%d][(%d, %d)]" % (k, x, y)) # pp.pprint(self.bonding_pairs[key]) index_start = i index_stop = len(s.pos) self.cleanup_bonding_pairs( key=key, index_start=index_start, index_stop=index_stop ) value = self.get_bonding_pairs( s=self.strings[key], index_start=index_start, index_stop=index_stop ) # pp.pprint(value) # pp.pprint(self.bonding_pairs[key]) for k, v in value.items(): if self.bonding_pairs[key].has_key(k): self.bonding_pairs[key][k] += v else: self.bonding_pairs[key][k] = v # self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs[key]) # print("== end ==") # pp.pprint(self.strings[key].pos) # pp.pprint(self.bonding_pairs[key].keys()) def cleanup_bonding_pairs(self, key, index_start, index_stop): rang = range(index_start, index_stop) for (x, y), l in self.bonding_pairs[key].items(): tmp = [] for i, (bonding_pair, w) in enumerate(l): if not bonding_pair[0] in rang: tmp.append(l[i]) if len(tmp) == 0: del self.bonding_pairs[key][(x, y)] else: self.bonding_pairs[key][(x, y)] = tmp def get_neighbor_xy(self, key): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ if len(self.bonding_pairs[key]) == 0: return False # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] bonding_pairs = [] b = reduce(operator.add, self.bonding_pairs[key].values()) # print(b) for (pair, w) in b: bonding_pairs.append(pair) weights.append(w) weights = np.array(weights) weights = weights / np.sum(weights) # print(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) # print(bonding_pairs[choiced_index]) return bonding_pairs[choiced_index] def get_bonding_pairs(self, s, index_start, index_stop): bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r], nny[r] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r_rev = (r + 3) % 6 if i == 0: w = self.dot(r_rev, s.vec[0]) W = np.exp(self.beta * w) self.__update_dict(bonding_pairs, (nx, ny), [[0, r_rev, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(s.vec[i - 1], r) W = np.exp(self.beta * w) self.__update_dict(bonding_pairs, (nx, ny), [[i, r], W]) return bonding_pairs
class Main(base): def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=1000): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary='periodic') self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) * Ly # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = True self.interval = interval def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # move head part of each strings (if possible) # TODO: Fix bug for s in self.strings: print "=== Start ===" print s.vec X = self.get_neighbor_xy(s) if not X: raise StopIteration # update starting position i, r, r_rev = X print i, r, r_rev s.vec[i] = r self.occupied[s.pos_x[-1], s.pos_y[-1]] = False if i == len(s.vec) - 1: s.vec = s.vec[:i] + [r_rev] else: s.vec = s.vec[:i + 1] + [r_rev] + s.vec[i + 1:-1] print s.vec print "=== Updated ===" s.update_pos() self.occupied[s.pos_x[i + 1], s.pos_y[i + 1]] = True ret = self.plot_string() if self.plot: ret = self.plot_string() return ret def get_neighbor_xy(self, s): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ neighbors_set = {} bonding_pairs = [] # sのx, y座標に関して for i, (x, y) in enumerate(s.pos): # それぞれの近傍点を取得 nnx, nny = self.lattice.neighbor_of(x, y) # 6方向全てに関して for r in range(6): nx, ny = nnx[r], nny[r] # 反射境界条件のとき除外される点の場合,次の近接点に if nx == -1 or ny == -1: continue # 既に占有されているとき,次の近接点に elif self.occupied[nx, ny]: continue # それ以外(近傍点のうち占有されていない点であるとき) # 既にstringの近傍として登録されている場合 elif neighbors_set.has_key((nx, ny)): # 一つ前に登録された点が現在の評価点の近傍点である場合 if neighbors_set[(nx, ny)][-1][0] == i - 1: # r_rev: 現在の点から近接点へのベクトル r_rev = (r + 3) % 6 # [i-1, r_{i}, r_{rev}] bonding_pairs.append([i - 1, neighbors_set[(nx, ny)][-1][1], r_rev]) neighbors_set[(nx, ny)].append((i, r)) # stringの近傍として登録されていない場合 # -> 新たに登録 else: if i == 0: # r_rev: 現在の点から近接点へのベクトル r_rev = (r + 3) % 6 bonding_pairs.append([- 1, neighbors_set[(nx, ny)][-1][1], r_rev]) neighbors_set[(nx, ny)] = [(i, r), ] # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] for i, r, r_rev in bonding_pairs: if i == 0 or i == len(s.vec) - 1: # 端の場合,定数 weight = 3 else: # 重みは内積の和で表現 weight = dot(s.vec[i - 1], r) + dot(r_rev, s.vec[i + 1]) + 1 weights.append(weight) weights = np.array(weights) weights = weights / np.sum(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) i, r, r_rev = bonding_pairs[choiced_index] return i, r, r_rev
class Eden(): def __init__(self, Lx=60, Ly=60, plot=True, frames=1000, boundary={'h': 'periodic', 'v': 'periodic'}, pre_function=None, post_function=None): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) center_x, center_y = Lx / 4, Ly / 2 self.points = [(center_x, center_y)] self.occupied[center_x, center_y] = True self.neighbors = list(map( tuple, np.array(self.lattice.neighbor_of(center_x, center_y)).T )) self.plot = plot self.interval = 1 self.frames = frames self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] def execute(self): if self.plot: self.plot_all() else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break def plot_all(self): """軸の設定,三角格子の描画 ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y X_min, X_max = min(self.lattice_X) - 0.1, max(self.lattice_X) + 0.1 Y_min, Y_max = min(self.lattice_Y) - 0.1, max(self.lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(self.lattice_X, self.lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.scatter = [ self.ax.plot([], [], 'k.')[0], self.ax.plot([], [], 'r.')[0] ] self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) def init_func(*arg): return self.scatter ani = animation.FuncAnimation(self.fig, self.update, frames=self.frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) plt.show() def plot_points(self): """self.pointsに格納されている格子座標を元にプロット """ ## self.points: [(x1, y1), (x2, y2), (x3, y3), ...] index = list(np.array(self.points).T) X = self.lattice_X[index] Y = self.lattice_Y[index] self.scatter[0].set_data(X, Y) index = list(np.array(self.neighbors).T) nx = self.lattice_X[index] ny = self.lattice_Y[index] self.scatter[1].set_data(nx, ny) return self.scatter def update(self, num=0): """funcanimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ if len(self.neighbors) == 0: print_debug("no neighbors") return False if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self)) x, y = self.neighbors.pop(random.randint(0, len(self.neighbors) - 1)) self.occupied[x, y] = True self.points.append((x, y)) new_n = set(((nx, ny) for nx, ny in np.array(self.lattice.neighbor_of(x, y)).T if nx != -1 and ny != -1)) updated_n = set(tuple(map(tuple, self.neighbors))) | new_n self.neighbors = [pos for pos in updated_n if not self.occupied[pos]] if self.post_function is not None: self.post_func_res.append(self.post_function(self)) if self.plot: return self.plot_points()
class Main(base): def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=1000): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={'h': 'periodic', 'v': 'periodic'}) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) * Ly # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = True self.interval = interval def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # move head part of each strings (if possible) # TODO: Fix bug for s in self.strings: print s.vec X = self.get_neighbor_xy(s) if not X: raise StopIteration # update starting position i, r, r_rev = X print i, r, r_rev s.vec[i] = r self.occupied[s.pos_x[-1], s.pos_y[-1]] = False if i == len(s.vec) - 1: s.vec = s.vec[:i] + [r_rev] else: s.vec = s.vec[:i + 1] + [r_rev] + s.vec[i + 1:-1] print len(s.vec) s.update_pos() self.occupied[s.pos_x[i + 1], s.pos_y[i + 1]] = True ret = self.plot_string() print self.occupied if self.plot: ret = self.plot_string() return ret def get_neighbor_xy(self, s): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ neighbors_set = {} bonding_pairs = [] # sのx, y座標に関して for i, (x, y) in enumerate(s.pos): # それぞれの近傍点を取得 nnx, nny = self.lattice.neighbor_of(x, y) # 6方向全てに関して for r in range(6): nx, ny = nnx[r], nny[r] # 反射境界条件のとき除外される点の場合,次の近接点に if nx == -1 or ny == -1: continue # 既に占有されているとき,次の近接点に elif self.occupied[nx, ny]: continue # それ以外(近傍点のうち占有されていない点であるとき) # 既にstringの近傍として登録されている場合 elif neighbors_set.has_key((nx, ny)): # 一つ前に登録された点が現在の評価点の近傍点である場合 if neighbors_set[(nx, ny)][-1][0] == i - 1: # r_rev: 現在の点から近接点へのベクトル r_rev = (r + 3) % 6 # [i-1, r_{i}, r_{rev}] bonding_pairs.append([i - 1, neighbors_set[(nx, ny)][-1][1], r_rev]) neighbors_set[(nx, ny)].append((i, r)) # stringの近傍として登録されていない場合 # -> 新たに登録 else: neighbors_set[(nx, ny)] = [(i, r), ] # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] for i, r, r_rev in bonding_pairs: if i == 0 or i == len(s.vec) - 1: # 端の場合,定数 weight = 3 else: # 重みは内積の和で表現 weight = dot(s.vec[i - 1], r) + dot(r_rev, s.vec[i + 1]) + 1 weights.append(weight) weights = np.array(weights) weights = weights / np.sum(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) i, r, r_rev = bonding_pairs[choiced_index] return i, r, r_rev
class Eden(): def __init__(self, Lx=60, Ly=60, plot=True, frames=1000, boundary={ 'h': 'periodic', 'v': 'periodic' }, pre_function=None, post_function=None): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) center_x, center_y = Lx / 4, Ly / 2 self.points = [(center_x, center_y)] self.occupied[center_x, center_y] = True self.neighbors = list( map(tuple, np.array(self.lattice.neighbor_of(center_x, center_y)).T)) self.plot = plot self.interval = 1 self.frames = frames self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] def execute(self): if self.plot: self.plot_all() else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break def plot_all(self): """軸の設定,三角格子の描画 ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) self.lattice_X = self.lattice.coordinates_x self.lattice_Y = self.lattice.coordinates_y X_min, X_max = min(self.lattice_X) - 0.1, max(self.lattice_X) + 0.1 Y_min, Y_max = min(self.lattice_Y) - 0.1, max(self.lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(self.lattice_X, self.lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.scatter = [ self.ax.plot([], [], 'k.')[0], self.ax.plot([], [], 'r.')[0] ] self.lattice_X = self.lattice_X.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice_Y.reshape(self.lattice.Lx, self.lattice.Ly) def init_func(*arg): return self.scatter ani = animation.FuncAnimation(self.fig, self.update, frames=self.frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) plt.show() def plot_points(self): """self.pointsに格納されている格子座標を元にプロット """ ## self.points: [(x1, y1), (x2, y2), (x3, y3), ...] index = list(np.array(self.points).T) X = self.lattice_X[index] Y = self.lattice_Y[index] self.scatter[0].set_data(X, Y) index = list(np.array(self.neighbors).T) nx = self.lattice_X[index] ny = self.lattice_Y[index] self.scatter[1].set_data(nx, ny) return self.scatter def update(self, num=0): """funcanimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ if len(self.neighbors) == 0: print_debug("no neighbors") return False if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self)) x, y = self.neighbors.pop(random.randint(0, len(self.neighbors) - 1)) self.occupied[x, y] = True self.points.append((x, y)) new_n = set(((nx, ny) for nx, ny in np.array(self.lattice.neighbor_of(x, y)).T if nx != -1 and ny != -1)) updated_n = set(tuple(map(tuple, self.neighbors))) | new_n self.neighbors = [pos for pos in updated_n if not self.occupied[pos]] if self.post_function is not None: self.post_func_res.append(self.post_function(self)) if self.plot: return self.plot_points()
class Main(base): """任意に設定したstringの近傍点に点を追加し成長させるモデル グラフ上で左端と右端に固定されたstringの近傍点を探索,ランダム(後には曲げ 弾性による重み付けの効果を追加)に選択し,stringを成長させていくモデル """ def __init__(self, Lx=40, Ly=40, boundary={ 'h': 'periodic', 'v': 'periodic' }, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta=2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError( "`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta # self.beta = 100. # まっすぐ(≒低温極限) # self.beta = 10. # まっすぐ # self.beta = 0. # 高温極限 # self.beta = 5. # 中間的 self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos)) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def _update_dict(self, dict, key, value): if dict.has_key(key): dict[key].append(value) else: dict[key] = [value] def dot(self, v, w): """0〜5で表された6つのベクトルの内積を計算する。 v, w (int): ベクトル(0〜5の整数で表す)""" if (w + 6 - v) % 6 == 0: return 1. elif (w + 6 - v) % 6 == 1 or (w + 6 - v) % 6 == 5: return 0.5 elif (w + 6 - v) % 6 == 2 or (w + 6 - v) % 6 == 4: return -0.5 elif (w + 6 - v) % 6 == 3: return -1. def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(lattice_X, lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [ self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines) ] if self.plot_surface: # self._num_surface = 1 # self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self._num_surface = 9 self.lines += [ self.ax.plot( [], [], '.', )[0] for i in range(self._num_surface) ] self.plot_string() def start_animation(self, filename=""): if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) if filename != "": try: ani.save(filename, codec="libx264", bitrate=-1, fps=30) except: print("Can't saved.") else: print("Animation is successfully saved at '%s'." % filename) else: plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y # sqrt(2^{2} + (1/2)^{2}) ~ 2.06 if dist_x > 2.1 * self.lattice.dx or dist_y > 2.1 * self.lattice.dx: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 num_plot_surface = 0 if self.plot_surface: if self._num_surface == 1: num_plot_surface = 1 neighbors = [] for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos in bonding_pairs.keys(): neighbors.append(pos) neighbors = list(np.array(neighbors).T) # print(neighbors) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] # print(X, Y) self.lines[-1].set_data(X, Y) # === else: w = {} for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos, bps in bonding_pairs.items(): for bp, _w in bps: if w.has_key(_w): w[_w].append(pos) else: w[_w] = [ pos, ] num_plot_surface = len(w) # W = sorted(w.keys(), reverse=True) sum_w = np.sum([len(w[_w]) for _w in w.keys()]) W = [(_w, (_w * len(w[_w])) / sum_w) for _w in w.keys()] ave_W = np.average(W, axis=0)[1] min_W = np.exp(self.beta * (-2.5)) / sum_w max_W = np.exp(self.beta * 2.5) / sum_w for k, (wi, _w) in enumerate(W): neighbors = list(np.array(w[wi]).T) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] self.lines[-(k + 1)].set_data(X, Y) ## color setting dw = _w - ave_W if min_W == ave_W: _c = 0.5 elif dw < 0: _c = (0.5 / (ave_W - min_W)) * (_w - min_W) else: _c = (0.5 / (max_W - ave_W)) * dw + 0.5 self.lines[-(k + 1)].set_color(cm.plasma(_c)) # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット if self.plot_surface: max_obj = len(self.lines) - num_plot_surface else: max_obj = len(self.lines) for j in range(i, max_obj): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # update each string for i, s in enumerate(self.strings): if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self, i, s)) ret = self.update_each_string(i) if self.post_function is not None: self.post_func_res.append(self.post_function(self, i, s)) if self.plot or self.save_video: return self.plot_string() def update_each_string(self, key): X = self.get_neighbor_xy(key) if not X: raise StopIteration # print(X) s = self.strings[key] # update positions if len(X) == 4: i, r_rev, nx, ny = X s.x, s.y = nx, ny s.insert(0, r_rev) x, y = s.pos_x[0], s.pos_y[0] elif len(X) == 2: i, r = X s.insert(i + 1, r) x, y = s.pos_x[-1], s.pos_y[-1] else: i, r, r_rev = X s.vec[i] = r s.insert(i + 1, r_rev) x, y = s.pos_x[i + 1], s.pos_y[i + 1] self.occupied[x, y] = True # print("== start == (%d, %d)" % (x, y)) # pp.pprint(self.bonding_pairs[key]) for k, bonding_pairs in self.bonding_pairs.items(): if bonding_pairs.has_key((x, y)): del self.bonding_pairs[k][(x, y)] # print("del self.bonding_pairs[%d][(%d, %d)]" % (k, x, y)) # pp.pprint(self.bonding_pairs[key]) index_start = i index_stop = len(s.pos) # print(index_start, index_stop) self.cleanup_bonding_pairs(key=key, index_start=index_start, index_stop=index_stop) value = self.get_bonding_pairs(s=self.strings[key], index_start=index_start, index_stop=index_stop) # pp.pprint(value) # pp.pprint(self.bonding_pairs[key]) for k, v in value.items(): if self.bonding_pairs[key].has_key(k): self.bonding_pairs[key][k] += v else: self.bonding_pairs[key][k] = v # pp.pprint(self.bonding_pairs[key]) # print("== end ==") # pp.pprint(self.strings[key].pos) # pp.pprint(self.bonding_pairs[key].keys()) def cleanup_bonding_pairs(self, key, index_start, index_stop): rang = range(index_start, index_stop) for pos, l in self.bonding_pairs[key].items(): tmp = [l[i] for i, (bp, w) in enumerate(l) if not bp[0] in rang] if len(tmp) == 0: del self.bonding_pairs[key][pos] else: self.bonding_pairs[key][pos] = tmp def get_neighbor_xy(self, key): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ if len(self.bonding_pairs[key]) == 0: return False # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] bonding_pairs = [] for (pair, w) in reduce(operator.add, self.bonding_pairs[key].values()): bonding_pairs.append(pair) weights.append(w) weights = np.array(weights) weights = weights / np.sum(weights) # print(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) # print(bonding_pairs[choiced_index]) return bonding_pairs[choiced_index] def calc_weight(self, s, i, r_i=None, r_rev=None): """ベクトルの内積を元に,Boltzmann分布に従って成長点選択の重みを決定 """ if (i == 1) and (not s.loop): w = self.dot(r_rev, s.vec[i]) - self.dot(s.vec[0], s.vec[1]) \ - self.weight_const elif (i == len(s.pos) - 1) and (not s.loop): w = self.dot(s.vec[i - 2], r_i) - \ self.dot(s.vec[i - 2], s.vec[i - 1]) - self.weight_const else: # w = self.dot(s.vec[i - 2], r_i) + self.dot(r_rev, s.vec[i % len(s.vec)]) w = (self.dot(s.vec[i - 2], r_i) + \ self.dot(r_rev, s.vec[i % len(s.vec)])) \ - (self.dot(s.vec[i - 2], s.vec[i - 1]) + \ self.dot(s.vec[i - 1], s.vec[i % len(s.vec)])) \ - self.weight_const W = np.exp(self.beta * w) return W def get_bonding_pairs(self, s, index_start, index_stop): bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) if s.loop and (0 in rang): rang.append(0) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r], nny[r] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r_rev = (r + 3) % 6 if not neighbors_dict.has_key((nx, ny)): if not s.loop: if i == 0: w = self.dot(r_rev, s.vec[0]) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[0, r_rev, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(s.vec[i - 1], r) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i, r], W]) neighbors_dict[(nx, ny)] = [ (i, r), ] else: if neighbors_dict[(nx, ny)][-1][0] == i - 1: r_i = neighbors_dict[(nx, ny)][-1][1] W = self.calc_weight(s, i, r_i, r_rev) self._update_dict(bonding_pairs, (nx, ny), [[i - 1, r_i, r_rev], W]) neighbors_dict[(nx, ny)].append((i, r)) return bonding_pairs
def __init__(self, Lx=40, Ly=40, boundary={ 'h': 'periodic', 'v': 'periodic' }, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta=2., interval=0, weight_const=0.5, strings=None, pre_function=None, post_function=None): self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) ## randomize randomize(self.lattice) ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.triang_standard = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError( "`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos)) self.bonding_pairs[key] = value self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close()
class Sim(Main): def __init__(self, Lx=40, Ly=40, boundary={ 'h': 'periodic', 'v': 'periodic' }, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta=2., interval=0, weight_const=0.5, strings=None, pre_function=None, post_function=None): self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary) ## randomize randomize(self.lattice) ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.triang_standard = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError( "`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos)) self.bonding_pairs[key] = value self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.ax.triplot(self.triang_random, color='#d5d5d5', lw=0.5) self.lines = [ self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines) ] if self.plot_surface: self._num_surface = 1 self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self.plot_string() def _vector(self, X1, Y1, X2, Y2): """Return 2-d vector from (X1, Y1) to (X2, Y2). Remark: X1, X2,... are grid coordinates and are not coordinates in real 2d space.""" x1, y1 = self.lattice_X[X1][Y1], self.lattice_Y[X1][Y1] x2, y2 = self.lattice_X[X2][Y2], self.lattice_Y[X2][Y2] return np.array([x2 - x1, y2 - y1]) def dot(self, vec1, vec2): """Calculate user-defined 'inner product' from the two 2d vectors `vec1` and `vec2`. """ ## normal inner product # res = np.dot(vec1, vec2) ## only depend on angle res = np.dot(vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2)) return res def get_bonding_pairs(self, s, index_start, index_stop): def _vec_(i): """Get vector from the point in string 's' indexed 'i' to the point indexed 'i+1'.""" X1, Y1 = s.pos[i] X2, Y2 = s.pos[i + 1] return self._vector(X1, Y1, X2, Y2) bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) if s.loop and (0 in rang): rang.append(0) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r_int in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r_int], nny[r_int] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r = self._vector(x, y, nx, ny) r_rev = self._vector(nx, ny, x, y) r_rev_int = (r_int + 3) % 6 if not neighbors_dict.has_key((nx, ny)): if not s.loop: if i == 0: w = self.dot(r_rev, _vec_(i % len(s.vec))) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[0, r_rev_int, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(_vec_(i - 1), r) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i, r_int], W]) neighbors_dict[(nx, ny)] = [ (i, r, r_int), ] else: if neighbors_dict[(nx, ny)][-1][0] == i - 1: r_i = neighbors_dict[(nx, ny)][-1][1] r_i_int = neighbors_dict[(nx, ny)][-1][2] if (i == 1) and (not s.loop): w = ( self.dot(r_i, r_rev) + \ self.dot(r_rev, _vec_(i)) ) - ( self.dot(_vec_(i - 1), _vec_(i)) ) elif (i == len(s.pos) - 1) and (not s.loop): w = ( self.dot(_vec_(i - 2), r_i) + \ self.dot(r_i, r_rev) ) - ( self.dot(_vec_(i - 2), _vec_(i - 1)) ) else: w = ( self.dot(_vec_(i - 2), r_i) + \ self.dot(r_i, r_rev) + \ self.dot(r_rev, _vec_(i % len(s.vec))) ) - ( self.dot(_vec_(i - 2), _vec_(i - 1)) + \ self.dot(_vec_(i - 1), _vec_(i % len(s.vec))) ) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i - 1, r_i_int, r_rev_int], W]) neighbors_dict[(nx, ny)].append((i, r, r_int)) return bonding_pairs
class Main: def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=50, plot=True): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary={ 'h': 'periodic', 'v': 'periodic' }) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = plot self.interval = interval def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') triang = tri.Triangulation(lattice_X, lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [ self.ax.plot([], [], marker='.', linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines) ] self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly) self.plot_string() def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y if dist_x > 2.1 * self.lattice.dx or dist_y > 2.1 * self.lattice.dy: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット for j in range(i, len(self.lines)): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # move head part of each strings (if possible) for s in self.strings: X = self.get_next_xy(s.x, s.y) if not X: raise StopIteration # update starting position x, y, vec = X rmx, rmy = s.follow((x, y, (vec + 3) % 6)) self.occupied[x, y] = True self.occupied[rmx, rmy] = False if self.plot: ret = self.plot_string() return ret def get_next_xy(self, x, y, *vec): nnx, nny = self.lattice.neighbor_of(x, y) vectors = [ i for i in range(6) if not (self.occupied[nnx[i], nny[i]] or (nnx[i] == -1 or nny[i] == -1)) ] if len(vectors) == 0: print_debug("no neighbors") return False # 確率的に方向を決定 vector = random.choice(vectors) # 点の格子座標を返す x, y = nnx[vector], nny[vector] return x, y, vector def create_random_strings(self, N=3, size=[10, 5, 3]): """Create N strings of each size is specified with 'size'. This process is equivalent to self-avoiding walk on triangular lattice. """ strings = [] n = 0 while n < N: # set starting point x = random.randint(0, self.lattice.Lx - 1) y = random.randint(0, self.lattice.Ly - 1) if self.occupied[x, y]: # reset # print_debug("(%d, %d) is occupied already. continue." % (x, y)) continue self.occupied[x, y] = True S = size[n] pos = [(x, y, np.random.choice(6))] trial, nmax = 0, 10 double = 0 while len(pos) < S: if trial > nmax: for _x, _y, vec in pos: self.occupied[_x, _y] = False # print_debug("All reset") break X = self.get_next_xy(x, y) if not X: if len(pos) == 1: # print_debug("len(pos) == 1") double = 0 trial += 1 break else: # print_debug("back one step") # print_debug(pos) if double == 1: # print_debug("two time. back two step") # print_debug(pos) oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) break oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) continue else: double = 0 x, y, vector = X self.occupied[x, y] = True pos.append((x, y, vector)) # print_debug("add step normally") # print_debug(pos) else: # print_debug("Done. Add string") vec = [v[2] for v in pos][1:] strings.append( String(self.lattice, n, pos[0][0], pos[0][1], vec=vec)) n += 1 return strings
class Main(base): def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], plot=True): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={'h': 'periodic', 'v': 'periodic'}) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = plot self.interval = 100 def update(self, num=0): # move head part of each strings (if possible) for s in self.strings: X = self.get_next_xy(s.x, s.y, s.vec[0]) if not X: raise StopIteration # update starting position x, y, vec = X rmx, rmy = s.follow((x, y, (vec + 3) % 6)) self.occupied[x, y] = True self.occupied[rmx, rmy] = False ret = self.plot_string() if self.plot: ret = self.plot_string() return ret def get_next_xy(self, x, y, vec): # 曲げ弾性の効果を再現するために,位置関係によって次の点の # 選ばれやすさが異なるようにする nnx, nny = self.lattice.neighbor_of(x, y) vectors = [i for i in range(6) if not self.occupied[nnx[i], nny[i]]] if len(vectors) == 0: print_debug("no neighbors") return False # 確率的に方向を決定 # 先頭ベクトルを0とした時の相対ベクトルごとの選ばれやすさを設定 # weights = [0., 1., 2., 3., 2., 1.] weights = [0., 0., 1., 4., 1., 0.] # weights = [0., 0., 2., 1., 2., 0.] # weights = [0., 0., 0., 1., 0., 0.] # 有効なものだけ取り出す weights = np.array([weights[(i + 6 - vec) % 6] for i in vectors]) # 規格化 weights = weights / np.sum(weights) # vectorsから一つ選択 vector = np.random.choice(vectors, p=weights) # 点の格子座標を返す x, y = nnx[vector], nny[vector] return x, y, vector def create_random_strings(self, N=3, size=[10, 5, 3]): """Create N strings of each size is specified with 'size'. This process is equivalent to self-avoiding walk on triangular lattice. """ strings = [] n = 0 while n < N: # set starting point x = random.randint(0, self.lattice.Lx - 1) y = random.randint(0, self.lattice.Ly - 1) if self.occupied[x, y]: # reset print_debug("(%d, %d) is occupied already. continue." % (x, y)) continue self.occupied[x, y] = True S = size[n] pos = [(x, y, np.random.choice(6))] trial, nmax = 0, 10 double = 0 while len(pos) < S: if trial > nmax: for _x, _y, vec in pos: self.occupied[_x, _y] = False print_debug("All reset") break X = self.get_next_xy(x, y, pos[-1][2]) if not X: if len(pos) == 1: print_debug("len(pos) == 1") double = 0 trial += 1 break else: print_debug("back one step") print_debug(pos) if double == 1: print_debug("two time. back two step") print_debug(pos) oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 print_debug(pos) break oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 print_debug(pos) continue else: double = 0 x, y, vector = X self.occupied[x, y] = True pos.append((x, y, vector)) print_debug("add step normally") print_debug(pos) else: print_debug("Done. Add string") vec = [v[2] for v in pos][1:] strings.append(String(self.lattice, n, pos[0][0], pos[0][1], vec=vec)) n += 1 return strings
class Main(base): """任意に設定したstringの近傍点に点を追加し成長させるモデル グラフ上で左端と右端に固定されたstringの近傍点を探索,ランダム(後には曲げ 弾性による重み付けの効果を追加)に選択し,stringを成長させていくモデル """ def __init__(self, Lx=40, Ly=40, boundary={'h': 'periodic', 'v': 'periodic'}, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta = 2., interval=1, weight_const=0.5, strings=None, pre_function=None, post_function=None): """Init function of Main class. Lx (int (even)): 格子のx方向(グラフではy軸)の格子点数 Ly (int (even)): 格子のy方向(グラフではx軸)の格子点数 """ # Create triangular lattice with given parameters # self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), # scale=float(max(Lx, Ly)), boundary=boundary) self.lattice = LT( np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary ) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError("`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta # self.beta = 100. # まっすぐ(≒低温極限) # self.beta = 10. # まっすぐ # self.beta = 0. # 高温極限 # self.beta = 5. # 中間的 self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos) ) # TODO: 隣接点がないとき,全体のシミュレーションを終了する # if len(value) == 0: # return False self.bonding_pairs[key] = value # pp.pprint(self.bonding_pairs) # print(self.strings[0].pos) # pp.pprint(self.bonding_pairs[0]) # pp.pprint(self.bonding_pairs) # return None self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def _update_dict(self, dict, key, value): if dict.has_key(key): dict[key].append(value) else: dict[key] = [value] def dot(self, v, w): """0〜5で表された6つのベクトルの内積を計算する。 v, w (int): ベクトル(0〜5の整数で表す)""" if (w + 6 - v) % 6 == 0: return 1. elif (w + 6 - v) % 6 == 1 or (w + 6 - v) % 6 == 5: return 0.5 elif (w + 6 - v) % 6 == 2 or (w + 6 - v) % 6 == 4: return -0.5 elif (w + 6 - v) % 6 == 3: return -1. def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: triang = tri.Triangulation(lattice_X, lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines)] if self.plot_surface: # self._num_surface = 1 # self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self._num_surface = 9 self.lines += [self.ax.plot([], [], '.', )[0] for i in range(self._num_surface)] self.plot_string() def start_animation(self, filename=""): if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) if filename != "": try: ani.save(filename, codec="libx264", bitrate=-1, fps=30) except: print("Can't saved.") else: print("Animation is successfully saved at '%s'." % filename) else: plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y # sqrt(2^{2} + (1/2)^{2}) ~ 2.06 if dist_x > 2.1 * self.lattice.dx or dist_y > 2.1 * self.lattice.dx: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 num_plot_surface = 0 if self.plot_surface: if self._num_surface == 1: num_plot_surface = 1 neighbors = [] for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos in bonding_pairs.keys(): neighbors.append(pos) neighbors = list(np.array(neighbors).T) # print(neighbors) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] # print(X, Y) self.lines[-1].set_data(X, Y) # === else: w = {} for bonding_pairs in self.bonding_pairs.values(): # print(bonding_pairs) for pos, bps in bonding_pairs.items(): for bp, _w in bps: if w.has_key(_w): w[_w].append(pos) else: w[_w] = [pos,] num_plot_surface = len(w) # W = sorted(w.keys(), reverse=True) sum_w = np.sum([len(w[_w]) for _w in w.keys()]) W = [(_w, (_w * len(w[_w])) / sum_w) for _w in w.keys()] ave_W = np.average(W, axis=0)[1] min_W = np.exp(self.beta * (-2.5)) /sum_w max_W = np.exp(self.beta * 2.5) /sum_w for k, (wi, _w) in enumerate(W): neighbors = list(np.array(w[wi]).T) X, Y = self.lattice_X[neighbors], self.lattice_Y[neighbors] self.lines[-(k + 1)].set_data(X, Y) ## color setting dw = _w - ave_W if min_W == ave_W: _c = 0.5 elif dw < 0: _c = (0.5 / (ave_W - min_W)) * (_w - min_W) else: _c = (0.5 / (max_W - ave_W)) * dw + 0.5 self.lines[-(k + 1)].set_color(cm.plasma(_c)) # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット if self.plot_surface: max_obj = len(self.lines) - num_plot_surface else: max_obj = len(self.lines) for j in range(i, max_obj): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # update each string for i, s in enumerate(self.strings): if self.pre_function is not None: self.pre_func_res.append(self.pre_function(self, i, s)) ret = self.update_each_string(i) if self.post_function is not None: self.post_func_res.append(self.post_function(self, i, s)) if self.plot or self.save_video: return self.plot_string() def update_each_string(self, key): X = self.get_neighbor_xy(key) if not X: raise StopIteration # print(X) s = self.strings[key] # update positions if len(X) == 4: i, r_rev, nx, ny = X s.x, s.y = nx, ny s.insert(0, r_rev) x, y = s.pos_x[0], s.pos_y[0] elif len(X) == 2: i, r = X s.insert(i + 1, r) x, y = s.pos_x[-1], s.pos_y[-1] else: i, r, r_rev = X s.vec[i] = r s.insert(i + 1, r_rev) x, y = s.pos_x[i + 1], s.pos_y[i + 1] self.occupied[x, y] = True # print("== start == (%d, %d)" % (x, y)) # pp.pprint(self.bonding_pairs[key]) for k, bonding_pairs in self.bonding_pairs.items(): if bonding_pairs.has_key((x, y)): del self.bonding_pairs[k][(x, y)] # print("del self.bonding_pairs[%d][(%d, %d)]" % (k, x, y)) # pp.pprint(self.bonding_pairs[key]) index_start = i index_stop = len(s.pos) # print(index_start, index_stop) self.cleanup_bonding_pairs( key=key, index_start=index_start, index_stop=index_stop ) value = self.get_bonding_pairs( s=self.strings[key], index_start=index_start, index_stop=index_stop ) # pp.pprint(value) # pp.pprint(self.bonding_pairs[key]) for k, v in value.items(): if self.bonding_pairs[key].has_key(k): self.bonding_pairs[key][k] += v else: self.bonding_pairs[key][k] = v # pp.pprint(self.bonding_pairs[key]) # print("== end ==") # pp.pprint(self.strings[key].pos) # pp.pprint(self.bonding_pairs[key].keys()) def cleanup_bonding_pairs(self, key, index_start, index_stop): rang = range(index_start, index_stop) for pos, l in self.bonding_pairs[key].items(): tmp = [l[i] for i, (bp, w) in enumerate(l) if not bp[0] in rang] if len(tmp) == 0: del self.bonding_pairs[key][pos] else: self.bonding_pairs[key][pos] = tmp def get_neighbor_xy(self, key): """Stringクラスのインスタンスsの隣接する非占有格子点の座標を取得する s (String): 対象とするStringクラスのインスタンス """ if len(self.bonding_pairs[key]) == 0: return False # bonding_pairsの選ばれやすさを適切に重みを付けて評価 weights = [] bonding_pairs = [] for (pair, w) in reduce(operator.add, self.bonding_pairs[key].values()): bonding_pairs.append(pair) weights.append(w) weights = np.array(weights) weights = weights / np.sum(weights) # print(weights) choiced_index = np.random.choice(range(len(weights)), p=weights) # print(bonding_pairs[choiced_index]) return bonding_pairs[choiced_index] def calc_weight(self, s, i, r_i=None, r_rev=None): """ベクトルの内積を元に,Boltzmann分布に従って成長点選択の重みを決定 """ if (i == 1) and (not s.loop): w = self.dot(r_rev, s.vec[i]) - self.dot(s.vec[0], s.vec[1]) \ - self.weight_const elif (i == len(s.pos) - 1) and (not s.loop): w = self.dot(s.vec[i - 2], r_i) - \ self.dot(s.vec[i - 2], s.vec[i - 1]) - self.weight_const else: # w = self.dot(s.vec[i - 2], r_i) + self.dot(r_rev, s.vec[i % len(s.vec)]) w = (self.dot(s.vec[i - 2], r_i) + \ self.dot(r_rev, s.vec[i % len(s.vec)])) \ - (self.dot(s.vec[i - 2], s.vec[i - 1]) + \ self.dot(s.vec[i - 1], s.vec[i % len(s.vec)])) \ - self.weight_const W = np.exp(self.beta * w) return W def get_bonding_pairs(self, s, index_start, index_stop): bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) if s.loop and (0 in rang): rang.append(0) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r], nny[r] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r_rev = (r + 3) % 6 if not neighbors_dict.has_key((nx, ny)): if not s.loop: if i == 0: w = self.dot(r_rev, s.vec[0]) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[0, r_rev, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(s.vec[i - 1], r) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i, r], W]) neighbors_dict[(nx, ny)] = [(i, r),] else: if neighbors_dict[(nx, ny)][-1][0] == i - 1: r_i = neighbors_dict[(nx, ny)][-1][1] W = self.calc_weight(s, i, r_i, r_rev) self._update_dict(bonding_pairs, (nx, ny), [[i - 1, r_i, r_rev], W]) neighbors_dict[(nx, ny)].append((i, r)) return bonding_pairs
class Sim(Main): def __init__(self, Lx=40, Ly=40, boundary={'h': 'periodic', 'v': 'periodic'}, size=[5, 4, 10, 12], plot=True, plot_surface=True, save_image=False, save_video=False, filename_image="", filename_video="", frames=1000, beta = 2., interval=0, weight_const=0.5, strings=None, pre_function=None, post_function=None): self.lattice = LT( np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary=boundary ) ## randomize randomize(self.lattice) ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.triang_standard = tri.Triangulation(self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx if strings is None: # Put the strings to the lattice self.strings = self.create_random_strings(len(size), size) else: self.strings = [String(self.lattice, **st) for st in strings] for string in self.strings: self.occupied[string.pos_x, string.pos_y] = True self.plot = plot self.plot_surface = plot_surface self.save_image = save_image self.save_video = save_video if self.save_image: if filename_image == "": raise AttributeError("`filename_image` is empty.") else: self.filename_image = filename_image if self.save_video: if self.plot: raise AttributeError("`save` and `plot` method can't be set both True.") if filename_video == "": raise AttributeError("`filename_video` is empty.") else: self.filename_video = filename_video self.interval = interval self.frames = frames # 逆温度 self.beta = beta self.weight_const = weight_const self.bonding_pairs = {i: {} for i in range(len(self.strings))} for key in self.bonding_pairs.keys(): value = self.get_bonding_pairs( s=self.strings[key], # indexes=[[0, len(self.strings[key].pos)]] index_start=0, index_stop=len(self.strings[key].pos) ) self.bonding_pairs[key] = value self.pre_function = pre_function self.post_function = post_function self.pre_func_res = [] self.post_func_res = [] # Plot triangular-lattice points, string on it, and so on if self.plot: self.plot_all() self.start_animation() elif self.save_video: self.plot_all() self.start_animation(filename=self.filename_video) else: t = 0 while t < self.frames: try: self.update() t += 1 except StopIteration: break if self.save_image: if not self.__dict__.has_key('fig'): self.plot_all() self.fig.savefig(self.filename_image) plt.close() # print("Image file is successfully saved at '%s'." % filename_image) def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') ## if the lattice size exceeds 200, don't draw triangular lattice. if max(self.lattice.Lx, self.lattice.Ly) < 200: self.ax.triplot(self.triang_random, color='#d5d5d5', lw=0.5) self.lines = [self.ax.plot([], [], linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines)] if self.plot_surface: self._num_surface = 1 self.lines.append(self.ax.plot([], [], '.', color='#ff0000')[0]) self.plot_string() def _vector(self, X1, Y1, X2, Y2): """Return 2-d vector from (X1, Y1) to (X2, Y2). Remark: X1, X2,... are grid coordinates and are not coordinates in real 2d space.""" x1, y1 = self.lattice_X[X1][Y1], self.lattice_Y[X1][Y1] x2, y2 = self.lattice_X[X2][Y2], self.lattice_Y[X2][Y2] return np.array([x2 - x1, y2 - y1]) def dot(self, vec1, vec2): """Calculate user-defined 'inner product' from the two 2d vectors `vec1` and `vec2`. """ ## normal inner product # res = np.dot(vec1, vec2) ## only depend on angle res = np.dot(vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2)) return res def get_bonding_pairs(self, s, index_start, index_stop): def _vec_(i): """Get vector from the point in string 's' indexed 'i' to the point indexed 'i+1'.""" X1, Y1 = s.pos[i] X2, Y2 = s.pos[i + 1] return self._vector(X1, Y1, X2, Y2) bonding_pairs = {} neighbors_dict = {} rang = range(index_start, index_stop) if s.loop and (0 in rang): rang.append(0) for i in rang: x, y = s.pos[i] nnx, nny = self.lattice.neighbor_of(x, y) for r_int in [0, 1, 2, 3, 4, 5]: nx, ny = nnx[r_int], nny[r_int] if self.occupied[nx, ny] or nx == -1 or ny == -1: continue r = self._vector(x, y, nx, ny) r_rev = self._vector(nx, ny, x, y) r_rev_int = (r_int + 3) % 6 if not neighbors_dict.has_key((nx, ny)): if not s.loop: if i == 0: w = self.dot(r_rev, _vec_(i % len(s.vec))) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[0, r_rev_int, nx, ny], W]) elif i == len(s.pos) - 1: w = self.dot(_vec_(i - 1), r) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i, r_int], W]) neighbors_dict[(nx, ny)] = [(i, r, r_int),] else: if neighbors_dict[(nx, ny)][-1][0] == i - 1: r_i = neighbors_dict[(nx, ny)][-1][1] r_i_int = neighbors_dict[(nx, ny)][-1][2] if (i == 1) and (not s.loop): w = ( self.dot(r_i, r_rev) + \ self.dot(r_rev, _vec_(i)) ) - ( self.dot(_vec_(i - 1), _vec_(i)) ) elif (i == len(s.pos) - 1) and (not s.loop): w = ( self.dot(_vec_(i - 2), r_i) + \ self.dot(r_i, r_rev) ) - ( self.dot(_vec_(i - 2), _vec_(i - 1)) ) else: w = ( self.dot(_vec_(i - 2), r_i) + \ self.dot(r_i, r_rev) + \ self.dot(r_rev, _vec_(i % len(s.vec))) ) - ( self.dot(_vec_(i - 2), _vec_(i - 1)) + \ self.dot(_vec_(i - 1), _vec_(i % len(s.vec))) ) W = np.exp(self.beta * w) self._update_dict(bonding_pairs, (nx, ny), [[i - 1, r_i_int, r_rev_int], W]) neighbors_dict[(nx, ny)].append((i, r, r_int)) return bonding_pairs
class Main: def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], interval=50, plot=True): # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=float(max(Lx, Ly)), boundary={'h': 'periodic', 'v': 'periodic'}) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = Lx # Put the strings to the lattice self.strings = self.create_random_strings(N, size) self.plot = plot self.interval = interval def plot_all(self): """軸の設定,三角格子の描画,線分描画要素の用意などを行う ここからFuncAnimationを使ってアニメーション表示を行うようにする """ if self.__dict__.has_key('frames'): frames = self.frames else: frames = 1000 self.fig, self.ax = plt.subplots(figsize=(8, 8)) lattice_X = self.lattice.coordinates_x lattice_Y = self.lattice.coordinates_y X_min, X_max = min(lattice_X) - 0.1, max(lattice_X) + 0.1 Y_min, Y_max = min(lattice_Y) - 0.1, max(lattice_Y) + 0.1 self.ax.set_xlim([X_min, X_max]) self.ax.set_ylim([Y_min, Y_max]) self.ax.set_xticklabels([]) self.ax.set_yticklabels([]) self.ax.set_aspect('equal') triang = tri.Triangulation(lattice_X, lattice_Y) self.ax.triplot(triang, color='#d5d5d5', lw=0.5) self.lines = [self.ax.plot([], [], marker='.', linestyle='-', color='black', markerfacecolor='black', markeredgecolor='black')[0] for i in range(self.number_of_lines)] self.lattice_X = self.lattice.coordinates_x.reshape(self.lattice.Lx, self.lattice.Ly) self.lattice_Y = self.lattice.coordinates_y.reshape(self.lattice.Lx, self.lattice.Ly) self.plot_string() def init_func(*arg): return self.lines ani = animation.FuncAnimation(self.fig, self.update, frames=frames, init_func=init_func, interval=self.interval, blit=True, repeat=False) plt.show() def plot_string(self): """self.strings内に格納されているStringを参照し,グラフ上に図示する """ # print self.string.pos, self.string.vec i = 0 # to count how many line2D object for s in self.strings: start = 0 for j, pos1, pos2 in zip(range(len(s.pos) - 1), s.pos[:-1], s.pos[1:]): dist_x = abs(self.lattice_X[pos1[0], pos1[1]] - self.lattice_X[pos2[0], pos2[1]]) dist_y = abs(self.lattice_Y[pos1[0], pos1[1]] - self.lattice_Y[pos2[0], pos2[1]]) # print j, pos1, pos2 # print dist_x, dist_y if dist_x > 2.1 * self.lattice.dx or dist_y > 2.1 * self.lattice.dy: x = s.pos_x[start:j + 1] y = s.pos_y[start:j + 1] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) start = j + 1 i += 1 else: x = s.pos_x[start:] y = s.pos_y[start:] X = [self.lattice_X[_x, _y] for _x, _y in zip(x, y)] Y = [self.lattice_Y[_x, _y] for _x, _y in zip(x, y)] self.lines[i].set_data(X, Y) i += 1 # 最終的に,iの数だけ線を引けばよくなる # それ以上のオブジェクトはリセット for j in range(i, len(self.lines)): self.lines[j].set_data([], []) return self.lines def update(self, num=0): """FuncAnimationから各フレームごとに呼び出される関数 1時間ステップの間に行う計算はすべてここに含まれる。 """ # move head part of each strings (if possible) for s in self.strings: X = self.get_next_xy(s.x, s.y) if not X: raise StopIteration # update starting position x, y, vec = X rmx, rmy = s.follow((x, y, (vec + 3) % 6)) self.occupied[x, y] = True self.occupied[rmx, rmy] = False if self.plot: ret = self.plot_string() return ret def get_next_xy(self, x, y, *vec): nnx, nny = self.lattice.neighbor_of(x, y) vectors = [i for i in range(6) if not (self.occupied[nnx[i], nny[i]] or (nnx[i] == -1 or nny[i] == -1)) ] if len(vectors) == 0: print_debug("no neighbors") return False # 確率的に方向を決定 vector = random.choice(vectors) # 点の格子座標を返す x, y = nnx[vector], nny[vector] return x, y, vector def create_random_strings(self, N=3, size=[10, 5, 3]): """Create N strings of each size is specified with 'size'. This process is equivalent to self-avoiding walk on triangular lattice. """ strings = [] n = 0 while n < N: # set starting point x = random.randint(0, self.lattice.Lx - 1) y = random.randint(0, self.lattice.Ly - 1) if self.occupied[x, y]: # reset # print_debug("(%d, %d) is occupied already. continue." % (x, y)) continue self.occupied[x, y] = True S = size[n] pos = [(x, y, np.random.choice(6))] trial, nmax = 0, 10 double = 0 while len(pos) < S: if trial > nmax: for _x, _y, vec in pos: self.occupied[_x, _y] = False # print_debug("All reset") break X = self.get_next_xy(x, y) if not X: if len(pos) == 1: # print_debug("len(pos) == 1") double = 0 trial += 1 break else: # print_debug("back one step") # print_debug(pos) if double == 1: # print_debug("two time. back two step") # print_debug(pos) oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) break oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) continue else: double = 0 x, y, vector = X self.occupied[x, y] = True pos.append((x, y, vector)) # print_debug("add step normally") # print_debug(pos) else: # print_debug("Done. Add string") vec = [v[2] for v in pos][1:] strings.append(String(self.lattice, n, pos[0][0], pos[0][1], vec=vec)) n += 1 return strings
class Main(base): def __init__(self, Lx=40, Ly=40, N=4, size=[5, 4, 10, 12], plot=True, beta=4.): self.plot = plot self.beta = beta self.interval = 1 self.frames = 20000 # Create triangular lattice with given parameters self.lattice = LT(np.zeros((Lx, Ly), dtype=np.int), scale=10., boundary={'h': 'periodic', 'v': 'periodic'} ) randomize(self.lattice) self.triang_standard = tri.Triangulation(self.lattice.coordinates_x, self.lattice.coordinates_y) self.triang_random = tri.Triangulation( self.lattice.coordinates_x, self.lattice.coordinates_y, triangles=self.triang_standard.triangles) self.lattice_X = self.lattice.coordinates_x.reshape( self.lattice.Lx, self.lattice.Ly ) self.lattice_Y = self.lattice.coordinates_y.reshape( self.lattice.Lx, self.lattice.Ly ) self.occupied = np.zeros((Lx, Ly), dtype=np.bool) self.number_of_lines = sum(size) # Put the strings to the lattice self.strings = self.create_random_strings(N, size) def _vector(self, X1, Y1, X2, Y2): """Return 2-d vector from (X1, Y1) to (X2, Y2). Remark: X1, X2,... are grid coordinates and are not coordinates in real 2d space.""" x1, y1 = self.lattice_X[X1][Y1], self.lattice_Y[X1][Y1] x2, y2 = self.lattice_X[X2][Y2], self.lattice_Y[X2][Y2] return np.array([x2 - x1, y2 - y1]) def _vec_(self, s, i): """Get vector from the point in string 's' indexed 'i' to the point indexed 'i+1'.""" X1, Y1 = s.pos[i] X2, Y2 = s.pos[i + 1] return self._vector(X1, Y1, X2, Y2) def dot(self, vec1, vec2): """Calculate user-defined 'inner product' from the two 2d vectors `vec1` and `vec2`. """ ## normal inner product # res = np.dot(vec1, vec2) ## only depend on angle res = np.dot(vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2)) return res def update(self, num=0): # move head part of each strings (if possible) for s in self.strings: X = self.get_next_xy(s.x, s.y, self._vec_(s, 0)) if not X: ## Stop all simulation # raise StopIteration ## Stop one string # continue ## Reverse head s.x, s.y = s.pos_x[-1], s.pos_y[-1] s.vec = [(vec + 3) % 6 for vec in reversed(s.vec)] s.update_pos() continue # update starting position x, y, vec = X rmx, rmy = s.follow((x, y, (vec + 3) % 6)) self.occupied[x, y] = True self.occupied[rmx, rmy] = False ret = self.plot_string() if self.plot: ret = self.plot_string() return ret def get_next_xy(self, x, y, vec): # 曲げ弾性の効果を再現するために,位置関係によって次の点の # 選ばれやすさが異なるようにする nnx, nny = self.lattice.neighbor_of(x, y) vectors = [i for i in range(6) if not self.occupied[nnx[i], nny[i]]] if len(vectors) == 0: # print_debug("no neighbors") return False # 確率的に方向を決定 if type(vec) == np.ndarray: weights = np.array([ np.exp( self.beta * self.dot(self._vector(nnx[i], nny[i], x, y), vec) ) for i in vectors]) else: weights = np.array([1.] * len(vectors)) # 規格化 weights = weights / np.sum(weights) # vectorsから一つ選択 selected_vector = np.random.choice(vectors, p=weights) # 点の格子座標を返す x, y = nnx[selected_vector], nny[selected_vector] return x, y, selected_vector def create_random_strings(self, N=3, size=[10, 5, 3]): """Create N strings of each size is specified with 'size'. This process is equivalent to self-avoiding walk on triangular lattice. """ strings = [] n = 0 while n < N: # set starting point x = random.randint(0, self.lattice.Lx - 1) y = random.randint(0, self.lattice.Ly - 1) if self.occupied[x, y]: # reset # print_debug("(%d, %d) is occupied already. continue." % (x, y)) continue self.occupied[x, y] = True S = size[n] pos = [(x, y, np.random.choice(6))] trial, nmax = 0, 10 double = 0 while len(pos) < S: if trial > nmax: for _x, _y, vec in pos: self.occupied[_x, _y] = False # print_debug("All reset") break if len(pos) == 1: X = self.get_next_xy(x, y, 1) else: X = self.get_next_xy(x, y, self._vector( pos[-2][0], pos[-2][1], pos[-1][0], pos[-1][1])) if not X: if len(pos) == 1: # print_debug("len(pos) == 1") double = 0 trial += 1 break else: # print_debug("back one step") # print_debug(pos) if double == 1: # print_debug("two time. back two step") # print_debug(pos) oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) break oldx, oldy, oldvec = pos[-1] del pos[-1] self.occupied[oldx, oldy] = False x, y, vector = pos[-1] trial += 1 # print_debug(pos) continue else: double = 0 x, y, vector = X self.occupied[x, y] = True pos.append((x, y, vector)) # print_debug("add step normally") # print_debug(pos) else: # print_debug("Done. Add string") vec = [v[2] for v in pos][1:] strings.append(String(self.lattice, n, pos[0][0], pos[0][1], vec=vec)) n += 1 return strings