def test_QuadraticForm_invariances(): #nu = numx.linspace(2.,-3,10) nu = numx.linspace(6., 1, 10) H = utils.symrand(nu) E, W = mdp.utils.symeig(H) q = utils.QuadraticForm(H) xmax, xmin = q.get_extrema(5.) e_w, e_sd = q.get_invariances(xmax) #print e_sd,nu[1:]-nu[0] assert_array_almost_equal(e_sd,nu[1:]-nu[0],6) assert_array_almost_equal(abs(e_w),abs(W[:,-2::-1]),6) e_w, e_sd = q.get_invariances(xmin) assert_array_almost_equal(e_sd,nu[-2::-1]-nu[-1],6) assert_array_almost_equal(abs(e_w),abs(W[:,1:]),6)
def _givens_angle_case1(self, m, n, covs, bica_bsfa, complete=0): # This function makes use of the constants computed in the paper # # R -> R # m -> \mu # n -> \nu # # Note that the minus sign before the angle phi is there because # in the paper the rotation convention is the opposite of ours. ncovs = covs.ncovs covs = covs.covs icaweights = self.icaweights sfaweights = self.sfaweights bica, bsfa = bica_bsfa Cmm, Cmn, Cnn = covs[m, m, :], covs[m, n, :], covs[n, n, :] d0 = (sfaweights * (Cmm*Cmm+Cnn*Cnn)).sum() d1 = 4*(sfaweights * (Cmm*Cmn-Cmn*Cnn)).sum() d2 = 2*(sfaweights * (2*Cmn*Cmn+Cmm*Cnn)).sum() e0 = 2*(icaweights * Cmn*Cmn).sum() e1 = 4*(icaweights * (Cmn*Cnn-Cmm*Cmn)).sum() e2 = (icaweights * ((Cmm-Cnn)*(Cmm-Cnn)-2*Cmn*Cmn)).sum() s24 = 0.25* (bsfa * d1 + bica * e1) c24 = 0.25* (bsfa *(d0-d2)+ bica *(e0-e2)) # compute the exact minimum # Note that 'arctan' finds always the first maximum # because s24sin(4p)+c24cos(4p)=const*cos(4p-arctan) # the minimum lies +pi/4 apart (period = pi/2). # In other words we want that: abs(minimum) < pi/4 phi4 = numx.arctan2(s24, c24) # use if-structure until bug in numx.sign is solved if phi4 >= 0: minimum = -0.25*(phi4-PI) else: minimum = -0.25*(phi4+PI) # compute all constants: R = self.output_dim dc = numx.zeros((ncovs, ), dtype = self.dtype) for t in range(ncovs): dg = covs[:R, :R, t].diagonal() dc[t] = (dg*dg).sum(axis=0) dc = ((dc-Cnn*Cnn-Cmm*Cmm)*sfaweights).sum() ec = numx.zeros((ncovs, ), dtype = self.dtype) for t in range(ncovs): triu_covs = _triu(covs[:R, :R, t], 1).ravel() ec[t] = ((triu_covs*triu_covs).sum() - covs[m, n, t]*covs[m, n, t]) ec = 2*(icaweights*ec).sum() a20 = 0.25*(bsfa*(4*dc+d2+3*d0)+bica*(4*ec+e2+3*e0)) minimum_contrast = a20+c24*cos(-4*minimum)+s24*sin(-4*minimum) npoints = 1000 if complete == 1: # Compute the contrast between -pi/2 and pi/2 # (useful for testing purposes) phi = numx.linspace(old_div(-PI,2), old_div(PI,2), npoints+1) contrast = a20 + c24*cos(-4*phi) + s24*sin(-4*phi) return phi, contrast, minimum, minimum_contrast elif complete == 2: phi = numx.linspace(old_div(-PI,4), old_div(PI,4), npoints+1) contrast = a20 + c24*cos(-4*phi) + s24*sin(-4*phi) return phi, contrast, minimum, minimum_contrast else: return minimum, minimum_contrast
def _givens_angle_case2(self, m, n, covs, bica_bsfa, complete=0): # This function makes use of the constants computed in the paper # # R -> R # m -> \mu # n -> \nu # # Note that the minus sign before the angle phi is there because # in the paper the rotation convention is the opposite of ours. ncovs = covs.ncovs covs = covs.covs icaweights = self.icaweights sfaweights = self.sfaweights R = self.output_dim bica, bsfa = bica_bsfa Cmm, Cmn, Cnn = covs[m, m, :], covs[m, n, :], covs[n, n, :] d0 = (sfaweights * Cmm*Cmm).sum() d1 = 4*(sfaweights * Cmn*Cmm).sum() d2 = 2*(sfaweights * (2*Cmn*Cmn + Cmm*Cnn)).sum() d3 = 4*(sfaweights * Cmn*Cnn).sum() d4 = (sfaweights * Cnn*Cnn).sum() e0 = 2*(icaweights * ((covs[:R, m, :]*covs[:R, m, :]).sum(axis=0) - Cmm*Cmm)).sum() e1 = 4*(icaweights * ((covs[:R, m, :]*covs[:R, n, :]).sum(axis=0) - Cmm*Cmn)).sum() e2 = 2*(icaweights * ((covs[:R, n, :]*covs[:R, n, :]).sum(axis=0) - Cmn*Cmn)).sum() s22 = 0.25 * bsfa*(d1+d3) + 0.5* bica*(e1) c22 = 0.5 * bsfa*(d0-d4) + 0.5* bica*(e0-e2) s24 = 0.125* bsfa*(d1-d3) c24 = 0.125* bsfa*(d0-d2+d4) # Compute the contrast function in a grid of angles to find a # first approximation for the minimum. Repeat two times # (effectively doubling the resolution). Note that we can do # that because we know we have a single minimum. # # npoints should not be too large otherwise the contrast # funtion appears to be constant. This is because we hit the # maximum resolution for the cosine function (ca. 1e-15) npoints = 100 left = old_div(-PI,2) - old_div(PI,(npoints+1)) right = old_div(PI,2) + old_div(PI,(npoints+1)) for iter in (1, 2): phi = numx.linspace(left, right, npoints+3) contrast = c22*cos(-2*phi)+s22*sin(-2*phi)+\ c24*cos(-4*phi)+s24*sin(-4*phi) minidx = contrast.argmin() left = phi[max(minidx-1, 0)] right = phi[min(minidx+1, len(phi)-1)] # The contrast is almost a parabola around the minimum. # To find the minimum we can therefore compute the derivative # (which should be a line) and calculate its root. # This step helps to overcome the resolution limit of the # cosine function and clearly improve the final result. der_left = 2*c22*sin(-2*left)- 2*s22*cos(-2*left)+\ 4*c24*sin(-4*left)- 4*s24*cos(-4*left) der_right = 2*c22*sin(-2*right)-2*s22*cos(-2*right)+\ 4*c24*sin(-4*right)-4*s24*cos(-4*right) if abs(der_left - der_right) < SQRT_EPS_D: minimum = phi[minidx] else: minimum = right - der_right*(right-left)/(der_right-der_left) dc = numx.zeros((ncovs,), dtype = self.dtype) for t in range(ncovs): dg = covs[:R, :R, t].diagonal() dc[t] = (dg*dg).sum(axis=0) dc = ((dc-Cmm*Cmm)*sfaweights).sum() ec = numx.zeros((ncovs, ), dtype = self.dtype) for t in range(ncovs): ec[t] = sum([covs[i, j, t]*covs[i, j, t] for i in range(R-1) for j in range(i+1, R) if i != m and j != m]) ec = 2*(ec*icaweights).sum() a20 = 0.125*bsfa*(3*d0+d2+3*d4+8*dc)+0.5*bica*(e0+e2+2*ec) minimum_contrast = a20+c22*cos(-2*minimum)+s22*sin(-2*minimum)+\ c24*cos(-4*minimum)+s24*sin(-4*minimum) if complete: # Compute the contrast between -pi/2 and pi/2 # (useful for testing purposes) npoints = 1000 phi = numx.linspace(old_div(-PI,2), old_div(PI,2), npoints+1) contrast = a20 + c22*cos(-2*phi) + s22*sin(-2*phi) +\ c24*cos(-4*phi) + s24*sin(-4*phi) return phi, contrast, minimum, minimum_contrast else: return minimum, minimum_contrast