def _derivativenorm(self): """Compute the derivative of the norm Returns ------- derivative : numpy array, shape (m_parameters,) """ w2 = cp.reshape(self.w,(self.n_features,self.d,self.D,self.D)) derivative = cp.zeros((self.n_features,self.d,self.D,self.D)) tmp=cp.zeros((self.n_features,self.D)) tmp2=cp.zeros((self.n_features,self.D)) tmp[0,:]=cp.sum(cp.square(w2[0,:,0,:]),0) for i in range(1,self.n_features-1): tmp[i,:]=cp.dot(tmp[i-1,:],cp.sum(cp.square(w2[i,:,:,:]),0)) tmp[self.n_features-1,:]=cp.inner(tmp[self.n_features-2,:], cp.sum(cp.square(w2[self.n_features-1,:,:,0]),0)) tmp2[self.n_features-1,:]=cp.sum(cp.square(w2[self.n_features-1,:,:,0]),0) for i in range(self.n_features-2,-1,-1): tmp2[i,:]=cp.dot(cp.sum(cp.square(w2[i,:,:,:]),0),tmp2[i+1,:]) tmp2[0,:]=cp.inner(cp.sum(cp.square(w2[0,:,0,:]),0),tmp2[1,:]) for j in range(self.d): derivative[0,j,0,:]=cp.multiply(tmp2[1,:],2*(w2[0,j,0,:])) derivative[self.n_features-1,j,:,0]=\ cp.multiply(tmp[self.n_features-2,:],2*(w2[self.n_features-1,j,:,0])) for i in range(1,self.n_features-1): temp3=cp.outer(tmp[i-1,:],tmp2[i+1,:]) for j in range(self.d): derivative[i,j,:,:]=cp.multiply(temp3,2*(w2[i,j,:,:])) return derivative.reshape(self.m_parameters)
def _check_symmetric(op1, op2, vec, eps): r2 = op1 * op2 s = cupy.inner(op2, op2) t = cupy.inner(vec, r2) z = abs(s - t) epsa = (s + eps) * eps ** (1.0 / 3.0) if z > epsa: return False return True
def _derivativenorm(self): """Compute the derivative of the norm Returns ------- derivative : numpy array, shape (m_parameters,) """ w2 = np.reshape(self.w, (self.n_features, self.d, self.D, self.D, self.mu)) derivative = np.zeros( (self.n_features, self.d, self.D, self.D, self.mu), dtype=np.complex128) tmp = np.zeros((self.n_features, self.D * self.D), dtype=np.complex128) tmp2 = np.zeros((self.n_features, self.D * self.D), dtype=np.complex128) tmp[0, :] = np.einsum('ijk,ilk->jl', w2[0, :, 0, :, :], np.conj(w2[0, :, 0, :, :])).reshape(self.D * self.D) for i in xrange(1, self.n_features - 1): newtmp = np.einsum('pimj,pklj->ikml', w2[i, :, :, :, :], np.conj(w2[i, :, :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp[i, :] = np.dot(tmp[i - 1, :], newtmp) newtmp = np.einsum('ijk,ilk->jl', w2[self.n_features - 1, :, :, 0, :], np.conj(w2[self.n_features - 1, :, :, 0, :])).reshape(self.D * self.D) mpscontracted = np.inner(tmp[self.n_features - 2, :], newtmp) tmp[self.n_features - 1, :] = mpscontracted tmp2[self.n_features - 1, :] = newtmp for i in xrange(self.n_features - 2, -1, -1): newtmp = np.einsum('pimj,pklj->ikml', w2[i, :, :, :, :], np.conj(w2[i, :, :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp2[i, :] = np.dot(newtmp, tmp2[i + 1, :]) newtmp = np.einsum('ijk,ilk->jl', w2[0, :, 0, :, :], np.conj(w2[0, :, 0, :, :])).reshape(self.D * self.D) tmp2[0, :] = np.inner(newtmp, tmp2[1, :]) for j in xrange(self.d): derivative[0, j, 0, :, :] = 2 * np.einsum( 'ij,il->lj', w2[0, j, 0, :, :], tmp2[1, :].reshape( self.D, self.D)) derivative[self.n_features-1,j,:,0,:]=\ 2*np.einsum('ij,il->lj',w2[self.n_features-1,j,:,0,:], tmp[self.n_features-2,:].reshape(self.D,self.D)) for i in xrange(1, self.n_features - 1): temp1 = tmp[i - 1, :].reshape(self.D, self.D) temp2 = tmp2[i + 1, :].reshape(self.D, self.D) for j in xrange(self.d): derivative[i, j, :, :, :] = 2 * np.einsum( 'ikm,ij,kl->jlm', w2[i, j, :, :, :], temp1, temp2) return derivative.reshape(self.m_parameters)
def _probability(self, x): """Unnormalized probability of one configuration P(x) Parameters ---------- x : numpy array, shape (n_features,) One configuration Returns ------- probability : float """ w2 = np.reshape(self.w, (self.n_features, self.d, self.D, self.D, self.mu)) tmp = w2[0, x[0], 0, :, :] tmp2 = np.einsum('ij,kj->ik', tmp, np.conj(tmp)).reshape(self.D * self.D) for i in xrange(1, self.n_features - 1): tmp = np.einsum('imj,klj->ikml', w2[i, x[i], :, :, :], np.conj(w2[i, x[i], :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp2 = np.dot(tmp2, tmp) tmp = np.einsum( 'ij,kj->ik', w2[self.n_features - 1, x[self.n_features - 1], :, 0, :], np.conj(w2[self.n_features - 1, x[self.n_features - 1], :, 0, :])).reshape(self.D * self.D) probability = np.abs(np.inner(tmp2, tmp)) return probability
def routine_gpu(data, sr, omega, morlet_frequency): n_chans, n_ts = data.shape data_gpu = cp.asarray(data) win = cp.array(mne.time_frequency.morlet(sr, [morlet_frequency], omega)[0]) data_preprocessed = cp.zeros_like(data_gpu, dtype=cp.complex64) surr_data = cp.zeros_like(data_preprocessed) for i in range(n_chans): data_preprocessed[i] = cusignal.fftconvolve(data_gpu[i], win, 'same') data_preprocessed[i] /= cp.abs(data_preprocessed[i]) surr_data[i] = cp.roll(data_preprocessed[i], np.random.randint(n_ts - 1)) plv = cp.inner(data_preprocessed, cp.conj(data_preprocessed)) / n_ts plv_surr = cp.inner(surr_data, cp.conj(surr_data)) / n_ts return cp.asnumpy(plv), cp.asnumpy(plv_surr)
def _derivative(self, x): """Compute the derivative of P(x) Parameters ---------- x : numpy array, shape (n_features,) One configuration Returns ------- derivative : numpy array, shape (m_parameters,) """ w2 = cp.reshape(self.w,(self.n_features,self.d,self.D,self.D)) derivative = cp.zeros((self.n_features,self.d,self.D,self.D)) #Store intermediate tensor contractions for the derivatives: #left to right and right to left #tmp stores the contraction of the first i+1 tensors from the left #in tmp[i,:,:], tmp2 the remaining tensors on the right #the mps contracted is the remaining contraction tmp[i-1]w[i]tmp2[i+1] tmp = cp.zeros((self.n_features,self.D)) tmp2 = cp.zeros((self.n_features,self.D)) tmp[0,:] = cp.square(w2[0,x[0],0,:]) for i in range(1,self.n_features-1): tmp[i,:] = cp.dot(tmp[i-1,:],cp.square(w2[i,x[i],:,:])) tmp[self.n_features-1,:] = cp.inner(tmp[self.n_features-2,:], cp.square(w2[self.n_features-1,x[self.n_features-1],:,0])) tmp2[self.n_features-1,:] = cp.square(w2[self.n_features-1, x[self.n_features-1],:,0]) for i in range(self.n_features-2,-1,-1): tmp2[i,:] = cp.dot(cp.square(w2[i,x[i],:]),tmp2[i+1,:]) tmp2[0,:] = cp.inner(cp.square(w2[0,x[0],0,:]),tmp2[1,:]) #The derivative of each tensor is the contraction of the other tensors derivative[0,x[0],0,:] = cp.multiply(tmp2[1,:],2*(w2[0,x[0],0,:])) derivative[self.n_features-1,x[self.n_features-1],:,0] = \ cp.multiply(tmp[self.n_features-2,:], 2*(w2[self.n_features-1,x[self.n_features-1],:,0])) for i in range(1,self.n_features-1): derivative[i,x[i],:,:]=cp.multiply(cp.outer(tmp[i-1,:], tmp2[i+1,:]),2*(w2[i,x[i],:])) return derivative.reshape(self.m_parameters)
def _computenorm(self): """Compute norm of probability distribution Returns ------- norm : float """ w2 = cp.reshape(self.w,(self.n_features,self.d,self.D,self.D)) tmp = cp.sum(cp.square(w2[0,:,0,:]),0) #First tensor for i in range(1,self.n_features-1): tmp = cp.dot(tmp,cp.sum(cp.square(w2[i,:,:,:]),0)) #MPS contraction norm = cp.inner(tmp,cp.sum(cp.square(w2[self.n_features-1,:,:,0]),0)) return norm
def _process_pair(self, x: int, y: int): n_bins = self.n_bins # compute mask of amplitude quantile for each sample in the data for i in range(n_bins): self.mask_buffer[i] = (self.data_amplitude_labels[x] == i) & (self.data_thresholded[x]) self.mask_buffer[i + n_bins] = (self.data_amplitude_labels[y] == i) & (self.data_thresholded[y]) # inner product of those masks is the same as compute sum of logical for each pair but without cycles => faster # however I dont like bool -> int type casting self.frequency_samples[:, :, x, y] = cp.inner( self.mask_buffer[:n_bins].astype(int), self.mask_buffer[n_bins:~0].astype(int)) self.frequency_samples[:, :, y, x] = self.frequency_samples[:, :, x, y] min_count = int(self.frequency_samples[:, :, x, y].min()) data_x = self.data_preprocessed[x] data_y = self.data_conj[y] for i, j in itertools.product(range(n_bins), range(n_bins)): cp.logical_and(self.mask_buffer[i], self.mask_buffer[j + n_bins], out=self.mask_buffer[~0]) # select data according to amplitude mask of both channels and truncate it to avoid PLV bias vals_x = data_x[self.mask_buffer[~0]][:min_count] vals_y = data_y[self.mask_buffer[~0]][:min_count] # just in case there are some label combinations without any samples; unluckly though # if vals_x.shape[0] == 0 or vals_y.shape[0] == 0: # continue self.frequency_plv[i, j, x, y] = self.frequency_plv[i, j, y, x] = cp.inner( vals_x, vals_y) / min_count
def _probability(self, x): """Unnormalized probability of one configuration P(x) Parameters ---------- x : cupy array, shape (n_features,) One configuration Returns ------- probability : float """ w2 = cp.reshape(self.w,(self.n_features,self.d,self.D,self.D)) tmp = cp.square(w2[0,x[0],0,:]) #First tensor for i in range(1,self.n_features-1): tmp = cp.dot(tmp,cupy.square(w2[i,x[i],:,:])) #MPS contraction probability = cp.inner(tmp,cupy.square(w2[self.n_features-1, x[self.n_features-1],:,0])) return probability
def gradient(self, input, expected_output): self.think(input) # calculate the activations from 'input' that are needed for the backpropagation algorithm nabla_w = [cp.zeros(w.shape) for w in self.weights] # initialise the matrices for the w_gradient nabla_b = [cp.zeros(b.shape) for b in self.biases] # initialise the matrices for the b_gradient z = [cp.dot(a, w) + b for a, w, b in zip(self.activations, self.weights, self.biases)] # a = sigmoid(z) ... nabla_a = self.activations[-1] - cp.array(expected_output) for i, a, z, w in zip(range(self.layer_number-2, -1, -1), self.activations[-2::-1], z[::-1], self.weights[::-1]): nabla_w[i] = cp.outer(a, nabla_a * sigmoid_derivative(z)) nabla_b[i] = nabla_a * sigmoid_derivative(z) nabla_a = cp.inner(nabla_a * sigmoid_derivative(z), w) nabla_b[-1] = cp.zeros_like(nabla_b[-1]) return (nabla_w, nabla_b)
def _computenorm(self): """Compute norm of probability distribution Returns ------- norm : float """ w2 = np.reshape(self.w, (self.n_features, self.d, self.D, self.D, self.mu)) tmp2 = np.einsum('ijk,ilk->jl', w2[0, :, 0, :, :], np.conj(w2[0, :, 0, :, :])).reshape(self.D * self.D) for i in xrange(1, self.n_features - 1): tmp = np.einsum('pimj,pklj->ikml', w2[i, :, :, :, :], np.conj(w2[i, :, :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp2 = np.dot(tmp2, tmp) tmp = np.einsum('ijk,ilk->jl', w2[self.n_features - 1, :, :, 0, :], np.conj(w2[self.n_features - 1, :, :, 0, :])).reshape(self.D * self.D) norm = np.abs(np.inner(tmp2, tmp)) return norm
def cosine_similarity(x, y): a = x.reshape((x.shape[1], )) b = y.reshape((y.shape[1], )) return cp.inner(a, b) / norm(a) * norm(b)
def inner(u,v): return cp.inner(u,v)
def f(x1, x2): return cupy.inner(x1, x2)
def f(x1, x2): return (cupy.inner(x1, x2) + coef)**power
def time_inner_trans_a_ac(self): np.inner(self.a, self.ac)
def _derivative(self, x): """Compute the derivative of P(x) Parameters ---------- x : numpy array, shape (n_features,) One configuration Returns ------- derivative : numpy array, shape (m_parameters,) """ w2 = np.reshape(self.w, (self.n_features, self.d, self.D, self.D, self.mu)) derivative = np.zeros( (self.n_features, self.d, self.D, self.D, self.mu), dtype=np.complex128) #Store intermediate tensor contractions for the derivatives: #left to right and right to left #tmp stores the contraction of the first i+1 tensors from the left #in tmp[i,:,:], tmp2 the remaining tensors on the right #the mps contracted is the remaining contraction tmp[i-1]w[i]tmp2[i+1] tmp = np.zeros((self.n_features, self.D * self.D), dtype=np.complex128) tmp2 = np.zeros((self.n_features, self.D * self.D), dtype=np.complex128) tmp[0, :] = np.einsum('ij,kj->ik', w2[0, x[0], 0, :, :], np.conj(w2[0, x[0], 0, :, :])).reshape(self.D * self.D) for i in xrange(1, self.n_features - 1): newtmp = np.einsum('imj,klj->ikml', w2[i, x[i], :, :, :], np.conj(w2[i, x[i], :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp[i, :] = np.dot(tmp[i - 1, :], newtmp) newtmp = np.einsum( 'ij,kj->ik', w2[self.n_features - 1, x[self.n_features - 1], :, 0, :], np.conj(w2[self.n_features - 1, x[self.n_features - 1], :, 0, :])).reshape(self.D * self.D) mpscontracted = np.inner(tmp[self.n_features - 2, :], newtmp) tmp[self.n_features - 1, :] = mpscontracted tmp2[self.n_features - 1, :] = newtmp for i in xrange(self.n_features - 2, -1, -1): newtmp = np.einsum('imj,klj->ikml', w2[i, x[i], :, :, :], np.conj(w2[i, x[i], :, :, :])).reshape( (self.D * self.D, self.D * self.D)) tmp2[i, :] = np.dot(newtmp, tmp2[i + 1, :]) newtmp = np.einsum('ij,kj->ik', w2[0, x[0], 0, :, :], np.conj(w2[0, x[0], 0, :, :])).reshape(self.D * self.D) tmp2[0, :] = np.inner(newtmp, tmp2[1, :]) #Now for each tensor, the derivative is the contraction of the rest of the tensors derivative[0, x[0], 0, :, :] = 2 * np.einsum('ij,il->lj', w2[0, x[0], 0, :, :], tmp2[1, :].reshape(self.D, self.D)) derivative[self.n_features-1,x[self.n_features-1],:,0,:]=\ 2*np.einsum('ij,il->lj',w2[self.n_features-1,x[self.n_features-1],:,0,:], tmp[self.n_features-2,:].reshape(self.D,self.D)) for i in xrange(1, self.n_features - 1): temp1 = tmp[i - 1, :].reshape(self.D, self.D) temp2 = tmp2[i + 1, :].reshape(self.D, self.D) derivative[i, x[i], :, :, :] = 2 * np.einsum( 'ikm,ij,kl->jlm', w2[i, x[i], :, :, :], temp1, temp2) return derivative.reshape(self.m_parameters)
def main(args): analysis_params = json.load(open(args.config_file)) high_freqs = np.logspace(2.35, 9, base=2, num=20, endpoint=False) low_freqs = np.logspace(1, 6.75, base=2, num=15, endpoint=False) epleptic_windows = pd.read_csv(analysis_params['epleptic_windows_file']) epleptic_windows[['Start', 'End']] = (epleptic_windows[['Start', 'End']] * 1000).astype(int) epleptic_windows = epleptic_windows.groupby('subject_number') root_path = os.path.join('../seeg_phases/data', 'SEEG_redux_BIDS') layout = BIDSLayout(root_path) for subject in layout.get(target='subject', extension='edf'): subject_code = int(subject.entities['subject']) res_fname = os.path.join( 'derivatives', 'pac_no_ez', 'pac_sub_{}.pickle'.format(subject.entities['subject'])) if os.path.exists(res_fname): print('Subject {} is processed!'.format( subject.entities['subject'])) continue montage_filename = os.path.join( subject.dirname, 'sub-{}_montage.tcsv'.format(subject.entities['subject'])) data_filename = subject.path if not (os.path.exists(montage_filename) and os.path.exists(data_filename)): print('Cannot find data for subject {}'.format( subject.entities['subject'])) continue bipo = make_bipolar(data_filename, montage_filename, analysis_params['lowpass_filter']) ref_mask = create_reference_mask(bipo) ref_mask_gpu = cp.array(ref_mask).astype(int) if subject_code in epleptic_windows.groups: subject_ez_windows = epleptic_windows.get_group(subject_code) subject_ez_samples_mask = get_ez_samples_mask( subject_ez_windows, bipo._data) else: subject_ez_samples_mask = np.ones(bipo._data.shape[1], dtype=bool) n_chans = len(bipo.ch_names) phase_amplitude_correlation = np.full(shape=(len(high_freqs), len(low_freqs), n_chans, n_chans), fill_value=np.nan) phase_amplitude_surrogates = np.full(shape=(len(high_freqs), len(low_freqs), n_chans, n_chans), fill_value=np.nan) data_gpu = cp.array(bipo._data[:, subject_ez_samples_mask]) for low_f in tqdm.tqdm(low_freqs, desc='Preprocessing...', leave=False): low_fname = 'temp/sub_{}_freq_{:.2f}.npy'.format( subject.entities['subject'], low_f) if os.path.exists(low_fname): continue data_low_f = filter_morlet_gpu(data_gpu, bipo.info['sfreq'], analysis_params['omega'], low_f) data_low_f /= cp.abs(data_low_f) data_low_f = cp.conj(data_low_f) cp.save(low_fname, data_low_f) data_low_f = None sr = bipo.info['sfreq'] bar = tqdm.tqdm(total=225, leave=False) for high_idx, high_f in enumerate(high_freqs): high_amp = cp.abs( filter_morlet_gpu(data_gpu, sr, analysis_params['omega'], high_f)) for low_idx, low_f in enumerate(low_freqs): if low_f > high_f: break low_fname = 'temp/sub_{}_freq_{:.2f}.npy'.format( subject.entities['subject'], low_f) slow_conj = cp.load(low_fname) high_amp_complex = filter_morlet_gpu(high_amp, sr, analysis_params['omega'], low_f) high_amp_complex /= cp.abs(high_amp_complex) corr = cp.inner(high_amp_complex, slow_conj) / slow_conj.shape[1] create_surrogate_inplace(high_amp_complex) corr_surr = cp.inner(high_amp_complex, slow_conj) / slow_conj.shape[1] phase_amplitude_correlation[high_idx, low_idx] = cp.asnumpy( cp.abs(corr) * ref_mask_gpu) phase_amplitude_surrogates[high_idx, low_idx] = cp.asnumpy( cp.abs(corr_surr) * ref_mask_gpu) bar.update(1) bar.close() res = { 'phase_amplitude_correlation': phase_amplitude_correlation, 'surrogate': phase_amplitude_surrogates, 'high_frequencies': high_freqs, 'low_frequencies': low_freqs, 'ref_mask': ref_mask, 'ch_names': bipo.ch_names } pickle.dump(res, open(res_fname, 'wb')) for low_f in tqdm.tqdm(low_freqs, desc='Preprocessing...', leave=False): low_fname = 'temp/sub_{}_freq_{:.2f}.npy'.format( subject.entities['subject'], low_f) if os.path.exists(low_fname): os.remove(low_fname)
def minres(A, b, x0=None, shift=0.0, tol=1e-5, maxiter=None, M=None, callback=None, check=False): """Uses MINimum RESidual iteration to solve ``Ax = b``. Args: A (ndarray, spmatrix or LinearOperator): The real or complex matrix of the linear system with shape ``(n, n)``. b (cupy.ndarray): Right hand side of the linear system with shape ``(n,)`` or ``(n, 1)``. x0 (cupy.ndarray): Starting guess for the solution. shift (int or float): If shift != 0 then the method solves ``(A - shift*I)x = b`` tol (float): Tolerance for convergence. maxiter (int): Maximum number of iterations. M (ndarray, spmatrix or LinearOperator): Preconditioner for ``A``. The preconditioner should approximate the inverse of ``A``. ``M`` must be :class:`cupy.ndarray`, :class:`cupyx.scipy.sparse.spmatrix` or :class:`cupyx.scipy.sparse.linalg.LinearOperator`. callback (function): User-specified function to call after each iteration. It is called as ``callback(xk)``, where ``xk`` is the current solution vector. Returns: tuple: It returns ``x`` (cupy.ndarray) and ``info`` (int) where ``x`` is the converged solution and ``info`` provides convergence information. .. seealso:: :func:`scipy.sparse.linalg.minres` """ A, M, x, b = _make_system(A, M, x0, b) matvec = A.matvec psolve = M.matvec n = b.shape[0] if maxiter is None: maxiter = n * 5 istop = 0 itn = 0 Anorm = 0 Acond = 0 rnorm = 0 ynorm = 0 xtype = x.dtype eps = cupy.finfo(xtype).eps Ax = matvec(x) r1 = b - Ax y = psolve(r1) beta1 = cupy.inner(r1, y) if beta1 < 0: raise ValueError('indefinite preconditioner') elif beta1 == 0: return x, 0 beta1 = cupy.sqrt(beta1) beta1 = beta1.get().item() if check: # see if A is symmetric if not _check_symmetric(A, Ax, x, eps): raise ValueError('non-symmetric matrix') # see if M is symmetric if not _check_symmetric(M, y, r1, eps): raise ValueError('non-symmetric preconditioner') oldb = 0 beta = beta1 dbar = 0 epsln = 0 qrnorm = beta1 phibar = beta1 rhs1 = beta1 rhs2 = 0 tnorm2 = 0 gmax = 0 gmin = cupy.finfo(xtype).max cs = -1 sn = 0 w = cupy.zeros(n, dtype=xtype) w2 = cupy.zeros(n, dtype=xtype) r2 = r1 while itn < maxiter: itn += 1 s = 1.0 / beta v = s * y y = matvec(v) y -= shift * v if itn >= 2: y -= (beta / oldb) * r1 alpha = cupy.inner(v, y) alpha = alpha.get().item() y -= (alpha / beta) * r2 r1 = r2 r2 = y y = psolve(r2) oldb = beta beta = cupy.inner(r2, y) beta = beta.get().item() beta = numpy.sqrt(beta) if beta < 0: raise ValueError('non-symmetric matrix') tnorm2 += alpha ** 2 + oldb ** 2 + beta ** 2 if itn == 1: if beta / beta1 <= 10 * eps: istop = -1 # Apply previous rotation Qk-1 to get # [deltak epslnk+1] = [cs sn][dbark 0 ] # [gbar k dbar k+1] [sn -cs][alfak betak+1]. oldeps = epsln delta = cs * dbar + sn * alpha # delta1 = 0 deltak gbar = sn * dbar - cs * alpha # gbar 1 = alfa1 gbar k epsln = sn * beta # epsln2 = 0 epslnk+1 dbar = - cs * beta # dbar 2 = beta2 dbar k+1 root = numpy.linalg.norm([gbar, dbar]) # Compute the next plane rotation Qk gamma = numpy.linalg.norm([gbar, beta]) # gammak gamma = max(gamma, eps) cs = gbar / gamma # ck sn = beta / gamma # sk phi = cs * phibar # phik phibar = sn * phibar # phibark+1 # Update x. denom = 1.0 / gamma w1 = w2 w2 = w w = (v - oldeps * w1 - delta * w2) * denom x += phi * w # Go round again. gmax = max(gmax, gamma) gmin = min(gmin, gamma) z = rhs1 / gamma rhs1 = rhs2 - delta * z rhs2 = - epsln * z # Estimate various norms and test for convergence. Anorm = numpy.sqrt(tnorm2) ynorm = cupy.linalg.norm(x) ynorm = ynorm.get().item() epsa = Anorm * eps epsx = Anorm * ynorm * eps diag = gbar if diag == 0: diag = epsa qrnorm = phibar rnorm = qrnorm if ynorm == 0 or Anorm == 0: test1 = numpy.inf else: test1 = rnorm / (Anorm * ynorm) # ||r|| / (||A|| ||x||) if Anorm == 0: test2 = numpy.inf else: test2 = root / Anorm # ||Ar|| / (||A|| ||r||) # Estimate cond(A). # In this version we look at the diagonals of R in the # factorization of the lower Hessenberg matrix, Q * H = R, # where H is the tridiagonal matrix from Lanczos with one # extra row, beta(k+1) e_k^T. Acond = gmax / gmin # See if any of the stopping criteria are satisfied. # In rare cases, istop is already -1 from above (Abar = const*I). if istop == 0: t1 = 1 + test1 # These tests work if tol < eps t2 = 1 + test2 if t2 <= 1: istop = 2 if t1 <= 1: istop = 1 if itn >= maxiter: istop = 6 if Acond >= 0.1 / eps: istop = 4 if epsx >= beta1: istop = 3 # epsr = Anorm * ynorm * tol # if rnorm <= epsx : istop = 2 # if rnorm <= epsr : istop = 1 if test2 <= tol: istop = 2 if test1 <= tol: istop = 1 if callback is not None: callback(x) if istop != 0: break if istop == 6: info = maxiter else: info = 0 return x, info
def basis_pursuit(A, b, tol=1e-4, niter=100, biter=32): """ solves min |x|_1 s.t. Ax=b using a Primal-Dual Interior Point Method Args: A: design matrix of size (d, n) b: measurement vector of length d tol: solver tolerance niter: maximum length of central path biter: maximum number of steps in backtracking line search Returns: vector of length n """ A = cp.asarray(A) b = cp.asarray(b) d, n = A.shape alpha = 0.01 beta = 0.5 mu = 10 e = cp.ones(n) gradf0 = cp.hstack([cp.zeros(n), e]) x = (A.T).dot(inv(A.dot(A.T))).dot(b) absx = cp.abs(x) u = 0.95 * absx + 0.1 * cp.max(absx) fu1 = x - u fu2 = -x - u lamu1 = -1.0 / fu1 lamu2 = -1.0 / fu2 v = A.dot(lamu2 - lamu1) ATv = (A.T).dot(v) sdg = -(cp.inner(fu1, lamu1) + cp.inner(fu2, lamu2)) tau = 2.0 * n * mu / sdg ootau = 1.0 / tau rcent = cp.hstack([-lamu1 * fu1, -lamu2 * fu2]) - ootau rdual = gradf0 + cp.hstack([lamu1 - lamu2 + ATv, -lamu1 - lamu2]) rpri = A.dot(x) - b resnorm = cp.sqrt(norm(rdual)**2 + norm(rcent)**2 + norm(rpri)**2) rdp = cp.empty(2 * n) rcp = cp.empty(2 * n) for i in range(niter): oofu1 = 1.0 / fu1 oofu2 = 1.0 / fu2 w1 = -ootau * (oofu2 - oofu1) - ATv w2 = -1.0 - ootau * (oofu1 + oofu2) w3 = -rpri lamu1xoofu1 = lamu1 * oofu1 lamu2xoofu2 = lamu2 * oofu2 sig1 = -lamu1xoofu1 - lamu2xoofu2 sig2 = lamu1xoofu1 - lamu2xoofu2 sigx = sig1 - sig2**2 / sig1 if cp.min(cp.abs(sigx)) == 0.0: break w1p = -(w3 - A.dot(w1 / sigx - w2 * sig2 / (sigx * sig1))) H11p = A.dot((A.T) * (e / sigx)[:, cp.newaxis]) if cp.min(sigx) > 0.0: dv = solve(H11p, w1p) else: dv = solve(H11p, w1p) dx = (w1 - w2 * sig2 / sig1 - (A.T).dot(dv)) / sigx Adx = A.dot(dx) ATdv = (A.T).dot(dv) du = (w2 - sig2 * dx) / sig1 dlamu1 = lamu1xoofu1 * (du - dx) - lamu1 - ootau * oofu1 dlamu2 = lamu2xoofu2 * (dx + du) - lamu2 - ootau * oofu2 s = 1.0 indp = cp.less(dlamu1, 0.0) indn = cp.less(dlamu2, 0.0) if cp.any(indp): s = min(s, cp.min(-lamu1[indp] / dlamu1[indp])) if cp.any(indn): s = min(s, cp.min(-lamu2[indn] / dlamu2[indn])) indp = cp.greater(dx - du, 0.0) indn = cp.greater(-dx - du, 0.0) if cp.any(indp): s = min(s, cp.min(-fu1[indp] / (dx[indp] - du[indp]))) if cp.any(indn): s = min(s, cp.min(-fu2[indn] / (-dx[indn] - du[indn]))) s = 0.99 * s for j in range(biter): xp = x + s * dx up = u + s * du vp = v + s * dv ATvp = ATv + s * ATdv lamu1p = lamu1 + s * dlamu1 lamu2p = lamu2 + s * dlamu2 fu1p = xp - up fu2p = -xp - up rdp[:n] = lamu1p - lamu2p + ATvp rdp[n:] = -lamu1p - lamu2p rdp += gradf0 rcp[:n] = -lamu1p * fu1p rcp[n:] = lamu2p * fu2p rcp -= ootau rpp = rpri + s * Adx s *= beta if (cp.sqrt(norm(rdp)**2 + norm(rcp)**2 + norm(rpp)**2) <= (1 - alpha * s) * resnorm): break else: break x = xp lamu1 = lamu1p lamu2 = lamu2p fu1 = fu1p fu2 = fu2p sdg = -(cp.inner(fu1, lamu1) + cp.inner(fu2, lamu2)) if sdg < tol: return cp.asnumpy(x) u = up v = vp ATv = ATvp tau = 2.0 * n * mu / sdg rpri = rpp rcent[:n] = lamu1 * fu1 rcent[n:] = lamu2 * fu2 ootau = 1.0 / tau rcent -= ootau rdual[:n] = lamu1 - lamu2 + ATv rdual[n:] = -lamu1 + lamu2 rdual += gradf0 resnorm = cp.sqrt(norm(rdual)**2 + norm(rcent)**2 + norm(rpri)**2) return cp.asnumpy(x)