def __init__(self, **kw): self.ncols = kw.get('ncols', None) self.nthreads = kw.get('nthreads', 1) self.random_seed = kw.get('rngseed', None) self.objf_choice = kw.get('objf choice', 'random') self.sol_type = kw.get('solution type', 'interior') self.add_noise = kw.get('add noise', False) ran_set_seed(self.random_seed) self.lp = lpsolve('make_lp', 0, self.ncols) #lpsolve('set_bounds_tighter', self.lp, True) # important so that we don't loosen tight bounds self.ineqs = [] self.eq_count = 0 self.leq_count = 0 self.geq_count = 0 self.bnd_count = 0 self.iteration = 0 self.prev_sol = None self.sum_ln_k = 0 self.curr_sol = None self.n_solutions = 0
def __init__(self, **kw): ncols = kw.get('ncols', None) nthreads = kw.get('nthreads', 1) rngseed = kw.get('rngseed', 0) self.objf_choice = kw.get('objf choice', 'random') self.sol_type = kw.get('solution type', 'interior') self.noise = kw.get('add noise', 1e-6) self.reset = kw.get('reset', False) Log("Samplex created") Log(" ncols = %i" % ncols) if ncols is not None: self.nVars = ncols self.nRight = self.nVars ran_set_seed(rngseed) self.random_seed = rngseed self.nthreads = nthreads Samplex.pivot = lambda s: csamplex.pivot(s) self.data = None self.dcopy = [] self.n_equations = 0 self.lhv = [] self.rhv = [] self.nVars = None # Number of variables + 1(constant column) [N] self.nLeft = 0 # Number of left hand variables [L] self.nSlack = 0 # Number of slack variables [S] self.nTemp = 0 # Number of temporary variables [Z] self.nRight = 0 # Number of right hand variables [R] self.eq_count = 0 self.leq_count = 0 self.geq_count = 0 self.eq_list = [] self.iteration = 0 self.moca = None self.sum_ln_k = 0 self.curr_sol = None self.n_solutions = 0 self.forbidden_variables = []
def __init__(self, **kw): ncols = kw.get('ncols', None) nthreads = kw.get('nthreads', 1) rngseed = kw.get('rngseed', 0) self.objf_choice = kw.get('objf choice', 'random') self.sol_type = kw.get('solution type', 'interior') self.noise = kw.get('add noise', 1e-6) self.reset = kw.get('reset', False) Log( "Samplex created" ) Log( " ncols = %i" % ncols ) if ncols is not None: self.nVars = ncols self.nRight = self.nVars ran_set_seed(rngseed) self.random_seed = rngseed self.nthreads = nthreads Samplex.pivot = lambda s: csamplex.pivot(s) self.data = None self.dcopy = [] self.n_equations = 0 self.lhv = [] self.rhv = [] self.nVars = None # Number of variables + 1(constant column) [N] self.nLeft = 0 # Number of left hand variables [L] self.nSlack = 0 # Number of slack variables [S] self.nTemp = 0 # Number of temporary variables [Z] self.nRight = 0 # Number of right hand variables [R] self.eq_count = 0 self.leq_count = 0 self.geq_count = 0 self.eq_list = [] self.iteration = 0 self.moca = None self.sum_ln_k = 0 self.curr_sol = None self.n_solutions = 0 self.forbidden_variables = []
def next(self, nsolutions=None): Log( '=' * 80 ) Log( 'Simplex Random Walk' ) Log( '=' * 80 ) Log( " %i equations" % len(self.eq_list) ) Log( "%6s %6s %6s\n%6i %6i %6i" % (">=", "<=", "=", self.geq_count, self.leq_count, self.eq_count) ) if nsolutions == 0: return assert nsolutions is not None dim = self.nVars dof = dim - self.eq_count burnin_len = max(10, int(self.burnin_factor * dof)) redo = max(100, int((dof ** self.redo_exp) * self.redo_factor)) nmodels = nsolutions nthreads = self.nthreads self.stride = int(dim+1) n_stored = 0 self.dim = dim self.dof = dof self.redo = redo self.burnin_len = burnin_len accept_rate = self.accept_rate accept_rate_tol = self.accept_rate_tol store = np.zeros((dim, 1+burnin_len), order='Fortran', dtype=np.float64) newp = np.zeros(dim, order='C', dtype=np.float64) eval = np.zeros(dim, order='C', dtype=np.float64) evec = np.zeros((dim,dim), order='F', dtype=np.float64) self.eqs = np.zeros((self.eqn_count+dim,dim+1), order='C', dtype=np.float64) for i,[c,e] in enumerate(self.eq_list): self.eqs[i,:] = e for i in xrange(dim): self.eqs[self.eqn_count+i,1+i] = 1 self.dist_eqs = np.zeros((self.eqn_count-self.eq_count,dim+1), order='C', dtype=np.float64) i=0 for c,e in self.eq_list: if c == 'eq': continue elif c == 'leq': p = e elif c == 'geq': p = -e self.dist_eqs[i,:] = p i += 1 Log( 'Using lpsolve %s' % lpsolve('lp_solve_version') ) Log( "random seed = %s" % self.random_seed ) Log( "threads = %s" % self.nthreads ) Log( "acceptence rate = %s" % self.accept_rate ) Log( "acceptence rate tolerance = %s" % self.accept_rate_tol ) Log( "dof = %s" % self.dof) Log( "sample distance = max(100,%s * %s^%s) = %s" % (self.redo_factor, self.dof, self.redo_exp, redo) ) Log( "starting twiddle = %s" % self.twiddle ) Log( "burn-in length = %s" % burnin_len ) time_begin_next = time.clock() #----------------------------------------------------------------------- # Create pseudo inverse matrix to reproject samples back into the # solution space. #----------------------------------------------------------------------- P = np.eye(dim) if self.eq_count > 0: self.A = np.zeros((self.eq_count, dim), order='C', dtype=np.float64) self.b = np.zeros(self.eq_count, order='C', dtype=np.float64) for i,[c,e] in enumerate(self.eq_list[:self.eq_count]): self.A[i] = e[1:] self.b[i] = e[0] self.Apinv = pinv(self.A) P -= np.dot(self.Apinv, self.A) else: self.A = None self.B = None self.Apinv = None ev, evec = eigh(P) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Find a point that is completely inside the simplex #----------------------------------------------------------------------- Log('Finding first inner point') time_begin_inner_point = time.clock() self.inner_point(newp) time_end_inner_point = time.clock() ok,fail_count = self.in_simplex(newp, eq_tol=1e-12, tol=0, verbose=1) assert ok self.avg0 = newp # eqs = self.eqs.copy('A') # eqs[:,1:] = np.dot(self.eqs[:,1:], evec) # print newp # S = zeros(self.eqs.shape[0]) # newp[:] = np.dot(evec.T, newp) # newp0 = newp.copy() # steps = newp.copy() # for q in range(100): # csamplex.refine_center(self, eqs, newp, ev, S, steps) # d = newp - newp0 # #print d # print norm(d) # #print # newp0 = newp.copy() # #assert 0 # newp[:] = np.dot(evec, newp) store[:,0] = newp n_stored = 1 q = MP.Queue() #----------------------------------------------------------------------- # Estimate the eigenvectors of the simplex #----------------------------------------------------------------------- Log('Estimating eigenvectors') time_begin_est_eigenvectors = time.clock() self.measured_ev(newp, ev, eval, evec) time_end_est_eigenvectors = time.clock() #----------------------------------------------------------------------- # Now we can start the random walk #----------------------------------------------------------------------- Log( "Getting solutions" ) ran_set_seed(self.random_seed) seeds = np.random.choice(1000000*nthreads, nthreads, replace=False) #----------------------------------------------------------------------- # Launch the threads #----------------------------------------------------------------------- threads = [] models_per_thread = nmodels // nthreads models_under = nmodels - nthreads*models_per_thread id,N = 0,0 while id < nthreads and N < nmodels: n = models_per_thread if id < models_under: n += 1 assert n > 0 Log( 'Thread %i gets %i' % (id,n) ) cmdq = MP.Queue() ackq = MP.Queue() thr = MP.Process(target=rwalk_burnin, args=(id, n, int(np.ceil(burnin_len/nthreads)), self, q, cmdq, ackq, newp, self.twiddle, eval.copy('A'), evec.copy('A'), seeds[id])) threads.append([thr,cmdq,ackq]) N += n id += 1 assert N == nmodels for thr,cmdq,_ in threads: thr.daemon=True thr.start() cmdq.put(['CONT']) def drainq(q): try: while True: q.get(block=False) except QueueEmpty: pass def pause_threads(threads): for _,cmdq,ackq in threads: cmdq.put(['WAIT']) assert ackq.get() == 'OK' def adjust_threads(i, cont_cmd): pause_threads(threads) drainq(q) Log( 'Computing eigenvalues... [%i/%i]' % (i, burnin_len) ) self.compute_eval_evec(store, eval, evec, n_stored) # new twiddle <-- average twiddle t = 0 for _,cmdq,ackq in threads: cmdq.put(['REQ TWIDDLE']) t += ackq.get() t /= len(threads) Log( 'New twiddle %f' % t ) for _,cmdq,_ in threads: cmdq.put(['NEW DATA', [eval.copy('A'), evec.copy('A'), t]]) cmdq.put([cont_cmd]) #----------------------------------------------------------------------- # Burn-in #----------------------------------------------------------------------- time_begin_burnin = time.clock() compute_eval_window = 2 * self.dof j = 0 k = -1 while n_stored < burnin_len+1: #for i in xrange(burnin_len): k,vecs,phase = q.get() #print 'Received ', len(vecs), ' from ', k for vec in vecs: j += 1 store[:, n_stored] = vec n_stored += 1 if n_stored == burnin_len+1: break if j == compute_eval_window: j = 0 adjust_threads(i+1,'CONT') compute_eval_window = int(0.1*burnin_len + 1) break if j != 0 and len(threads) < compute_eval_window: threads[k][1].put(['CONT']) time_end_burnin = time.clock() #----------------------------------------------------------------------- # Actual random walk #----------------------------------------------------------------------- time_begin_get_models = time.clock() adjust_threads(burnin_len, 'RWALK') i=0 while i < nmodels: k,vec,phase = q.get() if phase != 'RWALK': continue t = np.zeros(dim+1, order='Fortran', dtype=np.float64) t[1:] = vec i += 1 Log( '%i models left to generate' % (nmodels-i), overwritable=True) yield t time_end_get_models = time.clock() #----------------------------------------------------------------------- # Stop the threads and get their running times. #----------------------------------------------------------------------- time_threads = [] for thr,cmdq,ackq in threads: cmdq.put(['STOP']) m,t = ackq.get() assert m == 'TIME' time_threads.append(t) #thr.terminate() time_end_next = time.clock() max_time_threads = np.amax(time_threads) if time_threads else 0 avg_time_threads = np.mean(time_threads) if time_threads else 0 Log( '-'*80 ) Log( 'SAMPLEX TIMINGS' ) Log( '-'*80 ) Log( 'Initial inner point %.2fs' % (time_end_inner_point - time_begin_inner_point) ) Log( 'Estimate eigenvectors %.2fs' % (time_end_est_eigenvectors - time_begin_est_eigenvectors) ) Log( 'Burn-in %.2fs' % (time_end_burnin - time_begin_burnin) ) Log( 'Modeling %.2fs' % (time_end_get_models - time_begin_get_models) ) Log( 'Max/Avg thread time %.2fs %.2fs' % (max_time_threads, avg_time_threads) ) Log( 'Total wall-clock time %.2fs' % (time_end_next - time_begin_next) ) Log( '-'*80 )
def next(self, nsolutions=None): Log( '=' * 80 ) Log( 'Simplex Random Walk' ) Log( '=' * 80 ) Log( " %i equations" % len(self.eq_list) ) Log( "%6s %6s %6s\n%6i %6i %6i" % (">=", "<=", "=", self.geq_count, self.leq_count, self.eq_count) ) if nsolutions == 0: return assert nsolutions is not None dim = self.nVars dof = dim - self.eq_count burnin_len = max(10, int(self.burnin_factor * dof)) redo = max(100, int((dof ** self.redo_exp) * self.redo_factor)) nmodels = nsolutions nthreads = self.nthreads self.stride = int(dim+1) n_stored = 0 self.dim = dim self.dof = dof self.redo = redo self.burnin_len = burnin_len accept_rate = self.accept_rate accept_rate_tol = self.accept_rate_tol store = np.zeros((dim, 1+burnin_len), order='Fortran', dtype=np.float64) newp = np.zeros(dim, order='C', dtype=np.float64) eval = np.zeros(dim, order='C', dtype=np.float64) evec = np.zeros((dim,dim), order='F', dtype=np.float64) self.eqs = np.zeros((self.eqn_count+dim,dim+1), order='C', dtype=np.float64) for i,[c,e] in enumerate(self.eq_list): self.eqs[i,:] = e for i in xrange(dim): self.eqs[self.eqn_count+i,1+i] = 1 self.dist_eqs = np.zeros((self.eqn_count-self.eq_count,dim+1), order='C', dtype=np.float64) i=0 for c,e in self.eq_list: if c == 'eq': continue elif c == 'leq': p = e elif c == 'geq': p = -e self.dist_eqs[i,:] = p i += 1 Log( 'Using lpsolve %s' % lpsolve('lp_solve_version') ) Log( "random seed = %s" % self.random_seed ) Log( "threads = %s" % self.nthreads ) Log( "acceptence rate = %s" % self.accept_rate ) Log( "acceptence rate tolerance = %s" % self.accept_rate_tol ) Log( "dof = %s" % self.dof) Log( "sample distance = max(100,%s * %s^%s) = %s" % (self.redo_factor, self.dof, self.redo_exp, redo) ) Log( "starting twiddle = %s" % self.twiddle ) Log( "burn-in length = %s" % burnin_len ) time_begin_next = time.clock() #----------------------------------------------------------------------- # Create pseudo inverse matrix to reproject samples back into the # solution space. #----------------------------------------------------------------------- P = np.eye(dim) if self.eq_count > 0: self.A = np.zeros((self.eq_count, dim), order='C', dtype=np.float64) self.b = np.zeros(self.eq_count, order='C', dtype=np.float64) for i,[c,e] in enumerate(self.eq_list[:self.eq_count]): self.A[i] = e[1:] self.b[i] = e[0] self.Apinv = pinv(self.A) P -= np.dot(self.Apinv, self.A) else: self.A = None self.B = None self.Apinv = None ev, evec = eigh(P) #----------------------------------------------------------------------- #----------------------------------------------------------------------- # Find a point that is completely inside the simplex #----------------------------------------------------------------------- Log('Finding first inner point') time_begin_inner_point = time.clock() self.inner_point(newp) time_end_inner_point = time.clock() ok,fail_count = self.in_simplex(newp, eq_tol=1e-12, tol=0, verbose=1) assert ok self.avg0 = newp # eqs = self.eqs.copy('A') # eqs[:,1:] = np.dot(self.eqs[:,1:], evec) # print newp # S = zeros(self.eqs.shape[0]) # newp[:] = np.dot(evec.T, newp) # newp0 = newp.copy() # steps = newp.copy() # for q in range(100): # csamplex.refine_center(self, eqs, newp, ev, S, steps) # d = newp - newp0 # #print d # print norm(d) # #print # newp0 = newp.copy() # #assert 0 # newp[:] = np.dot(evec, newp) store[:,0] = newp n_stored = 1 #----------------------------------------------------------------------- # Estimate the eigenvectors of the simplex #----------------------------------------------------------------------- Log('Estimating eigenvectors') time_begin_est_eigenvectors = time.clock() self.measured_ev(newp, ev, eval, evec) time_end_est_eigenvectors = time.clock() #----------------------------------------------------------------------- # Now we can start the random walk #----------------------------------------------------------------------- Log( "Getting solutions" ) q = MP.Queue() ran_set_seed(self.random_seed) seeds = np.random.choice(1000000*nthreads, nthreads, replace=False) #----------------------------------------------------------------------- # Launch the threads #----------------------------------------------------------------------- threads = [] models_per_thread = nmodels // nthreads models_under = nmodels - nthreads*models_per_thread id,N = 0,0 while id < nthreads and N < nmodels: n = models_per_thread if id < models_under: n += 1 assert n > 0 Log( 'Thread %i gets %i' % (id,n) ) cmdq = MP.Queue() ackq = MP.Queue() thr = MP.Process(target=rwalk_burnin, args=(id, n, int(np.ceil(burnin_len/nthreads)), self, q, cmdq, ackq, newp, self.twiddle, eval.copy('A'), evec.copy('A'), seeds[id])) threads.append([thr,cmdq,ackq]) N += n id += 1 assert N == nmodels for thr,cmdq,_ in threads: thr.daemon=True thr.start() cmdq.put(['CONT']) def drainq(q): try: while True: q.get(block=False) except QueueEmpty: pass def pause_threads(threads): for _,cmdq,ackq in threads: cmdq.put(['WAIT']) assert ackq.get() == 'OK' def adjust_threads(i, cont_cmd): pause_threads(threads) drainq(q) Log( 'Computing eigenvalues... [%i/%i]' % (i, burnin_len) ) self.compute_eval_evec(store, eval, evec, n_stored) # new twiddle <-- average twiddle t = 0 for _,cmdq,ackq in threads: cmdq.put(['REQ TWIDDLE']) t += ackq.get() t /= len(threads) Log( 'New twiddle %f' % t ) for _,cmdq,_ in threads: cmdq.put(['NEW DATA', [eval.copy('A'), evec.copy('A'), t]]) cmdq.put([cont_cmd]) #----------------------------------------------------------------------- # Burn-in #----------------------------------------------------------------------- time_begin_burnin = time.clock() compute_eval_window = 2 * self.dof j = 0 for i in xrange(burnin_len): j += 1 k,vec = q.get() store[:, n_stored] = vec n_stored += 1 if j == compute_eval_window: j = 0 adjust_threads(i+1,'CONT') compute_eval_window = int(0.1*burnin_len + 1) elif len(threads) < compute_eval_window: threads[k][1].put(['CONT']) time_end_burnin = time.clock() #----------------------------------------------------------------------- # Actual random walk #----------------------------------------------------------------------- time_begin_get_models = time.clock() adjust_threads(burnin_len, 'RWALK') i=0 while i < nmodels: k,vec = q.get() t = np.zeros(dim+1, order='Fortran', dtype=np.float64) t[1:] = vec i += 1 Log( '%i models left to generate' % (nmodels-i), overwritable=True) yield t time_end_get_models = time.clock() #----------------------------------------------------------------------- # Stop the threads and get their running times. #----------------------------------------------------------------------- time_threads = [] for thr,cmdq,ackq in threads: cmdq.put(['STOP']) m,t = ackq.get() assert m == 'TIME' time_threads.append(t) #thr.terminate() time_end_next = time.clock() max_time_threads = np.amax(time_threads) if time_threads else 0 avg_time_threads = np.mean(time_threads) if time_threads else 0 Log( '-'*80 ) Log( 'SAMPLEX TIMINGS' ) Log( '-'*80 ) Log( 'Initial inner point %.2fs' % (time_end_inner_point - time_begin_inner_point) ) Log( 'Estimate eigenvectors %.2fs' % (time_end_est_eigenvectors - time_begin_est_eigenvectors) ) Log( 'Burn-in %.2fs' % (time_end_burnin - time_begin_burnin) ) Log( 'Modeling %.2fs' % (time_end_get_models - time_begin_get_models) ) Log( 'Max/Avg thread time %.2fs %.2fs' % (max_time_threads, avg_time_threads) ) Log( 'Total wall-clock time %.2fs' % (time_end_next - time_begin_next) ) Log( '-'*80 )