#cython: boundscheck=False #cython: wraparound=False #cython: cdivision=True """ cython_simulated_annealing.pyx cython implementation of a simulated annealing algorithm to find the optimal spike train order Note: using cython memoryviews (e.g. double[:]) instead of ndarray objects improves the performance of spike_distance by a factor of 10! Copyright 2015, Mario Mulansky Distributed under the BSD License """ """ To test whether things can be optimized: remove all yellow stuff in the html output:: cython -a cython_simulated_annealing.pyx which gives: cython_simulated_annealing.html """ import numpy as np cimport numpy as np from libc.math cimport exp from libc.math cimport fmod from libc.stdlib cimport rand from libc.stdlib cimport RAND_MAX DTYPE = np.float ctypedef np.float_t DTYPE_t def sim_ann_cython(double[:, :] D, double T_start, double T_end, double alpha): cdef long N = len(D) cdef double A = np.sum(np.triu(D, 0)) cdef long[:] p = np.arange(N) cdef double T = T_start cdef long iterations cdef long succ_iter cdef long total_iter = 0 cdef double delta_A cdef long ind1 cdef long ind2 while T > T_end: iterations = 0 succ_iter = 0 # equilibrate for 100*N steps or 10*N successful steps while iterations < 100*N and succ_iter < 10*N: # exchange two rows and cols # ind1 = np.random.randint(N-1) ind1 = rand() % (N-1) if ind1 < N-1: ind2 = ind1+1 else: # this can never happen! ind2 = 0 delta_A = -2*D[p[ind1], p[ind2]] if delta_A > 0.0 or exp(delta_A/T) > ((1.0*rand()) / RAND_MAX): # swap indices p[ind1], p[ind2] = p[ind2], p[ind1] A += delta_A succ_iter += 1 iterations += 1 total_iter += iterations T *= alpha # cool down if succ_iter == 0: # no successful step -> we believe we have converged break return p, A, total_iter