MATLAB может выполнять LU-разложение на разреженной прямоугольной матрице, используя [L, U, P, Q] = lu(A)
, но пакета R для этого пока нет.
Попытка использовать Matrix::lu()
для разреженной матрицы в R возвращает ошибку, сообщающую, что матрица должна быть квадратной.
Существует ли какой-либо аналог LU-разложения MATLAB на прямоугольной матрице, которая не имеет полного ранга в R? Чтобы уточнить, речь идет не о проблемах с памятью - если я встраиваю ее в единичную матрицу (см. этот вопрос), то Matrix::lu()
жалуется на то, что матрица сингулярна, в то время как MATLAB lu()
счастливо продолжает работу.
Проблема, которую я пытаюсь решить, состоит в том, чтобы реализовать в R конкретный эконометрический оценщик, которому требуется псевдообратный метод Мура-Пенроуза.
Псевдообратное преобразование Мура-Пенроуза pracma
не работает, поскольку матрица слишком велика.
Получение псевдоинверсии Мура-Пенроуза большой разреженной матрицы, по-видимому, также не решено, см. здесь.
Моя матрица имеет более одной единицы в любой строке и столбце.
?qr
?rankMatrix
Попробуйте pracma::lu()
.
@jay.sf, ?pracma::lu
, кажется, говорит, что ввод должен быть квадратным...
Я пытался сделать что-то похожее на RcppEigen, поскольку Eigen, по-видимому, может выполнять разреженное LU-разложение общих матриц, но мне не удалось преобразовать выходные данные в простые разреженные матрицы.
@BenBolker, достаточно честно...
может быть, опубликуйте свое частичное решение как (частичный) ответ и посмотрите, сможет ли кто-нибудь помочь вам двигаться дальше?
Я это сделал, а также добавил проблему, которую пытаюсь решить.
Возможно это может чем-то помочь
И встраивание его в единичную матрицу, и выполнение LU-разложения на A'A приводят к ошибке out of memory or near-singular
, в то время как MATLAB успешно продолжает работу. То, как меня учили разложению LU на уроках численного анализа в колледже, имело смысл только для квадратных матриц, поэтому я хотел бы понять, что MATLAB делает за кулисами в дополнение к возможности делать это в R.
Я буду рад возобновить работу, если вы сможете показать, почему связанный ответ не сработает для вас, кроме ограничений памяти, что является отдельной проблемой.
Речь идет о воспроизведении lu
из Matlab в R. На самом деле он не выходит из памяти, он сообщает об этом как о единственном числе, что и есть - но мы хотим, чтобы он выполнил факторизацию, раскрывающую ранг. Я приближаюсь к использованию UMFPACK, я отредактирую вопрос, если смогу.
@CarlWitthoft Я нашел решение и опубликую его как ответ, если вы повторно откроете вопрос. Мое решение решает как проблему выполнения LU-факторизации для сингулярной матрицы, так и проблему вычисления псевдообратного Мура-Пенроуза для разреженной матрицы с более чем одной единицей в данной строке/столбце, обе из которых не решены в двух связанных вопросы.
@kmf Отличная работа! Я снова открыл для тебя
Решено. Следующий код использует UMFPACK, ту же библиотеку, которую использует MATLAB. Чтобы получить нужные элементы, нам нужно добавить Control[UMFPACK_SCALE] = 0;
. Затем нам нужно зафиксировать размер полученной матрицы U в R.
#include <suitesparse/umfpack.h>
#include <Rcpp.h>
#include <algorithm>
#include <vector>
#include <iostream>
// [[Rcpp::export]]
Rcpp::List sparseLU(const std::vector<int> &Ap, const std::vector<int> &Ai, const std::vector<double> &Ax) {
int n = Ap.size() - 1;
int m = *std::max_element(Ai.begin(), Ai.end()) + 1;
int nnz = Ax.size();
double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO];
umfpack_di_defaults(Control);
Control[UMFPACK_PRL] = 2;
Control[UMFPACK_SCALE] = 0;
Control[UMFPACK_STRATEGY] = UMFPACK_STRATEGY_SYMMETRIC;
void *symbolic, *numeric;
int status;
status = umfpack_di_symbolic(m, n, Ap.data(), Ai.data(), Ax.data(), &symbolic, Control, Info);
if (status != UMFPACK_OK) {
umfpack_di_report_status(Control, status);
if (status < 0) {
Rcpp::stop("umfpack_di_symbolic failed with status %d", status);
}
}
status = umfpack_di_numeric(Ap.data(), Ai.data(), Ax.data(), symbolic, &numeric, Control, Info);
if (status != UMFPACK_OK) {
umfpack_di_report_status(Control, status);
if (status < 0) {
Rcpp::stop("umfpack_di_numeric failed with status %d", status);
umfpack_di_free_symbolic(&symbolic);
}
}
umfpack_di_free_symbolic(&symbolic);
int lnz, unz, nz_udiag;
status = umfpack_di_get_lunz(&lnz, &unz, &m, &n, &nz_udiag, numeric);
if (status != UMFPACK_OK) {
umfpack_di_report_status(Control, status);
if (status < 0) {
Rcpp::stop("umfpack_di_get_lunz failed with status %d", status);
umfpack_di_free_numeric(&numeric);
}
}
std::vector<int> Lp(m+1), Lj(lnz), Up(n+1), Ui(unz), P(m), Q(n);
std::vector<double> Lx(lnz), Ux(unz), D(std::min(m, n)), Rs(m);
int do_recip;
status = umfpack_di_get_numeric(Lp.data(), Lj.data(), Lx.data(), Up.data(), Ui.data(), Ux.data(), P.data(), Q.data(), D.data(), &do_recip, Rs.data(), numeric);
if (status != UMFPACK_OK) {
umfpack_di_report_status(Control, status);
if (status < 0) {
umfpack_di_free_numeric(&numeric);
Rcpp::stop("umfpack_di_get_numeric failed with status %d", status);
}
}
umfpack_di_free_numeric(&numeric);
Rcpp::List ret = Rcpp::List::create(
Rcpp::Named("L") = Rcpp::List::create(Rcpp::Named("j") = Lj, Rcpp::Named("p") = Lp, Rcpp::Named("x") = Lx),
Rcpp::Named("U") = Rcpp::List::create(Rcpp::Named("i") = Ui, Rcpp::Named("p") = Up, Rcpp::Named("x") = Ux),
Rcpp::Named("P") = P,
Rcpp::Named("Q") = Q
);
return ret;
}
Затем мы можем загрузить его в R вот так
# A is a sparseMatrix() from package Matrix
LUPQ <- sparseLU(A@p, A@i, A@x)
n <- ncol(A)
L <- sparseMatrix(j = LUPQ$L$j, p = LUPQ$L$p, x = LUPQ$L$x, index1 = FALSE)
U <- sparseMatrix(i = LUPQ$U$i, p = LUPQ$U$p, x = LUPQ$U$x, index1 = FALSE, dims = c(n, n))
Q <- sparseMatrix(i = LUPQ$Q + 1, j = 1:length(LUPQ$Q), x = 1)
Можете ли вы позволить себе преобразовать свою матрицу в плотную матрицу или это слишком непрактично?