Commit 5f8a2b3c by Carl Poelking

Network optimiser for dim-red.

parent d941ea9c
 ... ... @@ -3,13 +3,195 @@ import numpy as np import sklearn.manifold import sklearn.decomposition def compute_dist_matrix_2d(X, Y): dX = np.subtract.outer(X, X) dY = np.subtract.outer(Y, Y) return dX, dY, (dX*dX + dY*dY)**0.5 def compute_dist_matrix_3d(X, Y, Z): dX = np.subtract.outer(X, X) dY = np.subtract.outer(Y, Y) dZ = np.subtract.outer(Z, Z) return dX, dY, (dX*dX + dY*dY + dZ*dZ)**0.5 class BondNetwork(object): def __init__(self, tags, K, M): """ Args: tags (list of str, len=N): string labels for nodes K (np.ndarray, shape=(N,N)): kernel matrix, measuring similarity between nodes M (np.ndarray, shape=(N,)): list of node masses Example: >>> bond_network = BondNetwork(tags, K, M) >>> bond_network.initialise(method='kernelpca') >>> bond_network.integrate_md( >>> n_steps=7000, >>> rms_cut=1e-7, >>> dt=0.01, >>> dn_out=10, >>> append_traj=False) >>> ofs = open('confout.txt', 'w') >>> for i in range(bond_network.N): >>> ofs.write('%20s %3d %+1.7e %+1.7e\n' % ( >>> bond_network.tags[i], bond_network.M[i], >>> bond_network.X[i], bond_network.Y[i])) >>> ofs.close() """ self.tags = tags self.N = len(tags) self.K = K self.D = (1. - K**2 + 1e-7)**0.5 self.M = M # Masses # Exclusions and constraints self.have_excl = False self.have_constr = False assert K.shape[0] == self.N assert K.shape[1] == self.N def initialise(self, method): # Positions if method == 'random': X = np.random.uniform(size=self.N) Y = np.random.uniform(size=self.N) elif method in ['mds', 'kernelpca']: pos_mat = dimred_matrix( method=method, #'kernelpca', #'mds', kmat=self.K, distmat=self.D, symmetrize=True, outfile=None) self.X = pos_mat[:,0] self.Y = pos_mat[:,1] else: raise NotImplementedMethod(method) # Velocities self.Vx = np.zeros((self.N,), dtype='float64') self.Vy = np.zeros((self.N,), dtype='float64') # Equilibrium distances self.R0 = self.D # Harmonic force constants alpha = 10. # 10. beta = 1. k_t = 0.85 # 0.85 # 0.85 self.H = beta*0.5*( 1.+np.tanh(alpha*(K-k_t)) ) # Universal force constant? self.H.fill(0.28) # NOTE HACK np.fill_diagonal(self.H, 0.0) return def steep(self, n_steps, dt): """ TODO Turn this into a proper gradient descent (step size opt etc.) """ ofs = open('traj.xyz', 'w') for i in range(n_steps): # Compute distance matrix dX, dY, dR = compute_dist_matrix_2d(self.X, self.Y) # Compute forces Fx_harm = self.H * (dR - self.R0) * dX # Xij = xi-xj. Thus dR > R0 => Fij ~ -(xi-xj) is force experienced by j Fy_harm = self.H * (dR - self.R0) * dY Fx_harm = np.sum(Fx_harm, axis=1) Fy_harm = np.sum(Fy_harm, axis=1) # Integrate rms = (1./self.N * dt**2 * (np.dot(Fx_harm, Fx_harm) + np.dot(Fy_harm, Fy_harm)))**0.5 self.X = self.X - Fx_harm*dt self.Y = self.Y - Fy_harm*dt # Energy E = np.sum(0.5*self.H*(dR - self.R0)**2) print "Step %d %+1.7e %+1.7e" % (i, rms, E) # Trajectory scale = 100. ofs.write('%d\n\n' % (self.N)) for i in range(self.N): if 'OR' in self.tags[i]: type_ = 'O' else: type_ = 'C' ofs.write('%s %+1.7e %+1.7e 0.000\n' % (type_, self.X[i]*scale, self.Y[i]*scale)) ofs.close() return self.X, self.Y def exclude_below_mass(self, m_th): self.have_excl = True self.idcs_excl = np.where(self.M < m_th) self.idcs_noexcl = np.where(self.M >= m_th) def constrain_above_mass(self,m_th): self.have_constr = True self.idcs_constr = np.where(self.M > m_th) self.idcs_free = np.where(self.M <= m_th) def constrain_below_mass(self,m_th): self.have_constr = True self.idcs_constr = np.where(self.M < m_th) self.idcs_free = np.where(self.M >= m_th) def integrate_md(self, n_steps, dt, append_traj=False, dn_out=1, rms_cut=1.e-5): ofs = open('traj.xyz', 'a' if append_traj else 'w') gamma = 1. if self.have_excl: print "Noexcl", self.idcs_noexcl print "Constrain", self.idcs_constr for i in range(n_steps): # Compute distance matrix dX, dY, dR = compute_dist_matrix_2d(self.X, self.Y) # Update H self.H.fill(0.28) np.fill_diagonal(self.H, 0.0) bool_D = np.zeros(self.R0.shape, dtype='i4') bool_R = np.zeros(dR.shape, dtype='i4') bool_D[np.where(self.R0 > 0.8)] = 1 bool_R[np.where(dR > 0.8)] = 1 self.H[np.where((bool_D+bool_R) > 1)] = 0.0 # Compute forces Fx_harm = self.H * (dR - self.R0) * dX # Xij = xi-xj. Thus dR > R0 => Fij ~ -(xi-xj) is force experienced by j Fy_harm = self.H * (dR - self.R0) * dY # ... Exclusions if self.have_excl: Fx_harm[:,self.idcs_excl] = 0.0 Fy_harm[:,self.idcs_excl] = 0.0 # ... Sum pair forces Fx_harm = np.sum(Fx_harm, axis=1) Fy_harm = np.sum(Fy_harm, axis=1) # Integrate rms = (1./self.N * dt**2 * (np.dot(Fx_harm, Fx_harm) + np.dot(Fy_harm, Fy_harm)))**0.5 self.Vx = (1.-gamma*dt)*self.Vx - Fx_harm*dt #/self.M self.Vy = (1.-gamma*dt)*self.Vy - Fy_harm*dt #/self.M # ... Constraints if self.have_constr: self.Vx[self.idcs_constr] = 0.0 self.Vy[self.idcs_constr] = 0.0 delta_X = self.Vx*dt delta_Y = self.Vy*dt self.X = self.X + delta_X self.Y = self.Y + delta_Y rms = (np.sum(delta_X*delta_X+delta_Y*delta_Y)/self.N)**0.5 rms_max = np.max((delta_X*delta_X+delta_Y*delta_Y)**0.5) # Energy if self.have_excl: E = np.sum(0.5*self.H[self.idcs_noexcl][:,self.idcs_noexcl]*( dR[self.idcs_noexcl][:,self.idcs_noexcl] - self.R0[self.idcs_noexcl][:,self.idcs_noexcl])**2) else: E = np.sum(0.5*self.H*(dR - self.R0)**2) print "Step %d %+1.7e/%+1.7e %+1.7e" % (i, rms, rms_max, E) # Trajectory if i % dn_out == 0: scale = 100. ofs.write('%d\n\n' % (self.N)) for i in range(self.N): if 'OR' in self.tags[i]: type_ = 'O' else: type_ = 'C' ofs.write('%s %+1.7e %+1.7e 0.000\n' % (type_, self.X[i]*scale, self.Y[i]*scale)) if rms < rms_cut and rms_max < rms_cut: print "*** converged ***" break ofs.close() return self.X, self.Y def dimred_matrix(method, kmat=None, distmat=None, outfile=None, ix=None, symmetrize=False, prj_dimension=2): dmat = distmat if symmetrize: if type(kmat) != type(None): kmat = 0.5*(kmat+kmat.T) if type(dmat) != type(None): dmat = 0.5*(dmat+dmat.T) if type(distmat) != type(None): distmat = 0.5*(distmat+distmat.T) if method == 'mds': # MDS # http://scikit-learn.org/stable/modules/generated/sklearn.manifold.MDS.html#sklearn.manifold.MDS ... ... @@ -58,31 +240,21 @@ def diffusion_map(kmat, n_components, alpha=0.5): kmat_norm = kmat/kmat_diag kmat_norm = kmat_norm.T/kmat_diag np.fill_diagonal(kmat_norm, 1.) #print kmat_norm # Rescale kernel D0 = np.sum(kmat_norm, axis=1) D0_diag = np.zeros(kmat_norm.shape) np.fill_diagonal(D0_diag, D0) kmat_norm = kmat_norm/D0**alpha kmat_norm = kmat_norm.T/D0**alpha #print kmat_norm # Form Markov matrix D1 = np.sum(kmat_norm, axis=1) kmat_norm = (kmat_norm/D1).T #print kmat_norm #print np.sum(kmat_norm, axis=1) # Decompose import scipy.sparse evals, evecs = scipy.sparse.linalg.eigs(kmat_norm, n_components+1, which="LM") order = evals.argsort()[::-1] evals = evals[order] evecs = evecs.T[order].T #print evals #print evecs # Project return kmat_norm.dot(evecs[:,1:]) ... ...
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment