コード例 #1
0
ファイル: HODLR_Node.hpp プロジェクト: askhamwhat/HODLR
        /*!
         \brief Partial pivoted LU to construct low-rank.


         */
	void partial_Piv_LU(const int start_Row, const int start_Col, const int n_Rows, const int n_Cols, const double tolerance, int& computed_Rank, MatrixXcd& U, MatrixXcd& V) {

	/********************************/
	/*	PURPOSE OF EXISTENCE	*/
	/********************************/

	/*!
         Obtains the low-rank decomposition of the matrix to a desired tolerance using the partial pivoting LU algorithm, i.e., given a sub-matrix 'A' and tolerance 'epsilon', computes matrices 'U' and 'V' such that ||A-UV||_F < epsilon. The norm is Frobenius norm.
         */

	/************************/
	/*	INPUTS          */
	/************************/

	///	start_Row	-	Starting row of the sub-matrix.
	///	start_Col	-	Starting column of the sub-matrix.
	///	n_Rows		-	Number of rows of the sub-matrix.
	///	n_Cols		-	Number of columns of the sub-matrix.
	///	tolerance	-	Tolerance of low-rank approximation.

	/************************/
	/*	OUTPUTS		*/
	/************************/

	///	computed_Rank	-	Rank obtained for the given tolerance.
	///	U		-	Matrix forming the column basis.
	///	V		-	Matrix forming the row basis.

		/// If the matrix is small enough, do not do anything
		int tolerable_Rank =   5;
		if (n_Cols <= tolerable_Rank){
			kernel->get_Matrix(start_Row, start_Col, n_Rows, n_Cols, U);
			V               =   MatrixXcd::Identity(n_Cols, n_Cols);
			computed_Rank   =   n_Cols;
			return;
		}
		else if (n_Rows <= tolerable_Rank){
			U               =   MatrixXcd::Identity(n_Rows, n_Rows);
			kernel->get_Matrix(start_Row, start_Col, n_Rows, n_Cols, V);
			computed_Rank   =   n_Rows;
			return;
		}

		vector<int> rowIndex;	///	This stores the row indices, which have already been used.
		vector<int> colIndex;	///	This stores the column indices, which have already been used.
		vector<VectorXcd> u;	///	Stores the column basis.
		vector<VectorXcd> v;	///	Stores the row basis.

		srand (time(NULL));
                complex<double> max, unused_max, Gamma;

		/*  INITIALIZATION  */

		/// Initialize the matrix norm and the the first row index
		double matrix_Norm  =   0;
		rowIndex.push_back(0);

		int pivot;

		computed_Rank   =   0;

		VectorXcd a, row, col;

		double row_Squared_Norm, row_Norm, col_Squared_Norm, col_Norm;

		/// Repeat till the desired tolerance is obtained
		do {
			/// Generation of the row
			kernel->get_Matrix_Row(start_Col, n_Cols, start_Row+rowIndex.back(), a);
			/// Row of the residuum and the pivot column
			row =   a;
			for (int l=0; l<computed_Rank; ++l) {
				row =   row-u[l](rowIndex.back())*v[l];
			}

			pivot   =   kernel->max_Abs_Vector(row, colIndex, max);

			int max_tries  =   100;
			int count      =   0;
			int count1     =   0;

			/// This randomization is needed if in the middle of the algorithm the row happens to be exactly the linear combination of the previous rows.
			while (abs(max)<tolerance && count < max_tries) {
				int new_rowIndex;
				rowIndex.pop_back();
				do {
					new_rowIndex   =   rand()%n_Rows;
					++count1;
				} while (find(rowIndex.begin(),rowIndex.end(),new_rowIndex)!=rowIndex.end() && count1 < max_tries);
				count1  =   0;
				rowIndex.push_back(new_rowIndex);

				/// Generation of the row
				kernel->get_Matrix_Row(start_Col, n_Cols, start_Row+rowIndex.back(), a);

				/// Row of the residuum and the pivot column
				row =   a;
				for (int l=0; l<computed_Rank; ++l) {
					row =   row-u[l](rowIndex.back())*v[l];
				}
				pivot   =   kernel->max_Abs_Vector(row, colIndex, max);
				++count;
			}

			if (count == max_tries) break;

			count = 0;

			colIndex.push_back(pivot);

			/// Normalizing constant
			Gamma   =   1.0/(max);

			/// Generation of the column
			kernel->get_Matrix_Col(start_Row, n_Rows, start_Col+colIndex.back(), a);

			/// Column of the residuum and the pivot row
			col =   a;
			for (int l=0; l<computed_Rank; ++l) {
				col =   col-v[l](colIndex.back())*u[l];
			}
			pivot   =   kernel->max_Abs_Vector(col, rowIndex, unused_max);

			/// This randomization is needed if in the middle of the algorithm the columns happens to be exactly the linear combination of the previous columns.
			while (abs(max)<tolerance && count < max_tries) {
				colIndex.pop_back();
				int new_colIndex;
				do {
					new_colIndex   =   rand()%n_Cols;
				} while (find(colIndex.begin(),colIndex.end(),new_colIndex)!=colIndex.end() && count1 < max_tries);
				count1  =   0;
				colIndex.push_back(new_colIndex);

				/// Generation of the column
				kernel->get_Matrix_Col(start_Row, n_Rows, start_Col+colIndex.back(), a);

				/// Column of the residuum and the pivot row
				col =   a;
				for (int l=0; l<computed_Rank; ++l) {
					col =   col-u[l](colIndex.back())*v[l];
				}
				pivot   =   kernel->max_Abs_Vector(col, rowIndex, unused_max);
				++count;
			}

			if (count == max_tries) break;

			count = 0;

			rowIndex.push_back(pivot);

			/// New vectors
			u.push_back(Gamma*col);
			v.push_back(row);

			/// New approximation of matrix norm
			row_Squared_Norm    =   row.squaredNorm();
			row_Norm            =   sqrt(row_Squared_Norm);

			col_Squared_Norm    =   col.squaredNorm();
			col_Norm            =   sqrt(col_Squared_Norm);

			matrix_Norm         =   matrix_Norm +   abs(Gamma*Gamma*row_Squared_Norm*col_Squared_Norm);

			for (int j=0; j<computed_Rank; ++j) {
				matrix_Norm     =   matrix_Norm +   2.0*abs(u[j].dot(u.back()))*abs(v[j].dot(v.back()));
			}
			++computed_Rank;
		} while (row_Norm*col_Norm > abs(max)*tolerance*matrix_Norm && computed_Rank <= fmin(n_Rows, n_Cols));

		/// If the computed_Rank is close to full-rank then return the trivial full-rank decomposition
		if (computed_Rank>=fmin(n_Rows, n_Cols)) {
			if (n_Rows < n_Cols) {
				U   =   MatrixXcd::Identity(n_Rows,n_Rows);
				kernel->get_Matrix(start_Row, start_Col, n_Rows, n_Cols, V);
				computed_Rank   =   n_Rows;
				return;
			}
			else {
				kernel->get_Matrix(start_Row, start_Col, n_Rows, n_Cols, U);
				V   =   MatrixXcd::Identity(n_Cols,n_Cols);
				computed_Rank   =   n_Cols;
				return;
			}
		}

		U   =   MatrixXcd(n_Rows,computed_Rank);
		V   =   MatrixXcd(computed_Rank,n_Cols);
		for (int j=0; j<computed_Rank; ++j) {
			U.col(j)    =   u[j];
			V.row(j)    =   v[j];
		}
	};
コード例 #2
0
void UnbiasedSquaredPhaseLagIndex::compute(ConnectivitySettings::IntermediateTrialData& inputData,
                                           QVector<QPair<int,MatrixXcd> >& vecPairCsdSum,
                                           QVector<QPair<int,MatrixXd> >& vecPairCsdImagSignSum,
                                           QMutex& mutex,
                                           int iNRows,
                                           int iNFreqs,
                                           int iNfft,
                                           const QPair<MatrixXd, VectorXd>& tapers)
{
    if(inputData.vecPairCsdImagSign.size() == iNRows) {
        //qDebug() << "UnbiasedSquaredPhaseLagIndex::compute - vecPairCsdImagSign was already computed for this trial.";
        return;
    }

    inputData.vecPairCsdImagSign.clear();

    int i,j;

    // Calculate tapered spectra if not available already
    // This code was copied and changed modified Utils/Spectra since we do not want to call the function due to time loss.
    if(inputData.vecTapSpectra.size() != iNRows) {
        inputData.vecTapSpectra.clear();

        RowVectorXd vecInputFFT, rowData;
        RowVectorXcd vecTmpFreq;

        MatrixXcd matTapSpectrum(tapers.first.rows(), iNFreqs);

        QVector<Eigen::MatrixXcd> vecTapSpectra;

        FFT<double> fft;
        fft.SetFlag(fft.HalfSpectrum);

        for (i = 0; i < iNRows; ++i) {
            // Substract mean
            rowData.array() = inputData.matData.row(i).array() - inputData.matData.row(i).mean();

            // Calculate tapered spectra if not available already
            for(j = 0; j < tapers.first.rows(); j++) {
                vecInputFFT = rowData.cwiseProduct(tapers.first.row(j));
                // FFT for freq domain returning the half spectrum and multiply taper weights
                fft.fwd(vecTmpFreq, vecInputFFT, iNfft);
                matTapSpectrum.row(j) = vecTmpFreq * tapers.second(j);
            }

            inputData.vecTapSpectra.append(matTapSpectrum);
        }
    }

    // Compute CSD
    if(inputData.vecPairCsd.isEmpty()) {
        double denomCSD = sqrt(tapers.second.cwiseAbs2().sum()) * sqrt(tapers.second.cwiseAbs2().sum()) / 2.0;

        bool bNfftEven = false;
        if (iNfft % 2 == 0){
            bNfftEven = true;
        }

        MatrixXcd matCsd = MatrixXcd(iNRows, iNFreqs);

        for (i = 0; i < iNRows; ++i) {
            for (j = i; j < iNRows; ++j) {
                // Compute CSD (average over tapers if necessary)
                matCsd.row(j) = inputData.vecTapSpectra.at(i).cwiseProduct(inputData.vecTapSpectra.at(j).conjugate()).colwise().sum() / denomCSD;

                // Divide first and last element by 2 due to half spectrum
                matCsd.row(j)(0) /= 2.0;
                if(bNfftEven) {
                    matCsd.row(j).tail(1) /= 2.0;
                }
            }

            inputData.vecPairCsd.append(QPair<int,MatrixXcd>(i,matCsd));
            inputData.vecPairCsdImagSign.append(QPair<int,MatrixXd>(i,matCsd.imag().cwiseSign()));
        }

        mutex.lock();

        if(vecPairCsdSum.isEmpty()) {
            vecPairCsdSum = inputData.vecPairCsd;
            vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
        } else {
            for (int j = 0; j < vecPairCsdSum.size(); ++j) {
                vecPairCsdSum[j].second += inputData.vecPairCsd.at(j).second;
                vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
            }
        }

        mutex.unlock();
    } else {
        if(inputData.vecPairCsdImagSign.isEmpty()) {
            for (i = 0; i < inputData.vecPairCsd.size(); ++i) {
                inputData.vecPairCsdImagSign.append(QPair<int,MatrixXd>(i,inputData.vecPairCsd.at(i).second.imag().cwiseSign()));
            }

            mutex.lock();

            if(vecPairCsdImagSignSum.isEmpty()) {
                vecPairCsdImagSignSum = inputData.vecPairCsdImagSign;
            } else {
                for (int j = 0; j < vecPairCsdImagSignSum.size(); ++j) {
                    vecPairCsdImagSignSum[j].second += inputData.vecPairCsdImagSign.at(j).second;
                }
            }

            mutex.unlock();
        }
    }
}