From 3590eda1e759ac452379159e5412801e5c77f7de Mon Sep 17 00:00:00 2001 From: jvallve <jvallve@224674b8-e365-4e73-a4a8-558dbbfec58c> Date: Fri, 19 Jun 2015 15:03:53 +0000 Subject: [PATCH] work in progress... solvers --- src/examples/test_iQR.cpp | 191 +++++++++++++++++++++++++------------- 1 file changed, 129 insertions(+), 62 deletions(-) diff --git a/src/examples/test_iQR.cpp b/src/examples/test_iQR.cpp index a3f776f7d..c611fdfb0 100644 --- a/src/examples/test_iQR.cpp +++ b/src/examples/test_iQR.cpp @@ -33,13 +33,38 @@ using namespace Eigen; -void erase_sparse_block(SparseMatrix<double>& original, const unsigned int& row, const unsigned int& Nrows, const unsigned int& col, const unsigned int& Ncols) +class block_pruning { - for (uint i = row; i < row + Nrows; i++) - for (uint j = col; j < row + Ncols; j++) - original.coeffRef(i,j) = 0.0; + public: + int col, row, Nrows, Ncols; + block_pruning(int _col, int _row, int _Nrows, int _Ncols) : + col(_col), + row(_row), + Nrows(_Nrows), + Ncols(_Ncols) + { + // + } + bool operator()(int i, int j, double) const + { + return (i < row || i > row + Nrows-1) || (j < col || j > col + Ncols-1); + } +}; - original.makeCompressed(); +void erase_sparse_block(SparseMatrix<double>& original, const unsigned int& row, const unsigned int& col, const unsigned int& Nrows, const unsigned int& Ncols) +{ + // prune all non-zero elements that not satisfy the 'keep' operand + // elements that are not in the block rows or are not in the block columns should be kept + //original.prune([](int i, int j, double) { return (i < row || i > row + Nrows-1) || (j < col || j > col + Ncols-1); }); + + block_pruning bp(row, col, Nrows, Ncols); + original.prune(bp); + +// for (uint i = row; i < row + Nrows; i++) +// for (uint j = col; j < row + Ncols; j++) +// original.coeffRef(i,j) = 0.0; +// +// original.prune(0); } void add_sparse_block(const MatrixXd& ins, SparseMatrix<double>& original, const unsigned int& row, const unsigned int& col) @@ -50,14 +75,6 @@ void add_sparse_block(const MatrixXd& ins, SparseMatrix<double>& original, const original.coeffRef(r + row, c + col) += ins(r,c); } -//void add_sparse_row(const MatrixXd& ins, SparseMatrix<double>& original, const unsigned int& row, const unsigned int& col) -//{ -// for (uint r=0; r<ins.rows(); ++r) -// for (uint c = 0; c < ins.cols(); c++) -// if (ins(r,c) != 0) -// original.coeffRef(r + row, c + col) += ins(r,c); -//} - void permutation_2_block_permutation(const PermutationMatrix<Dynamic, Dynamic, int> &perm_nodes, PermutationMatrix<Dynamic, Dynamic, int> &perm_variables, const int dim) { ArrayXXi idx(dim, perm_nodes.indices().rows()); @@ -96,20 +113,20 @@ int main(int argc, char *argv[]) int dim = atoi(argv[2]); // Problem variables - SparseQR < SparseMatrix<double>, NaturalOrdering<int>> solver, solver2; + SparseQR < SparseMatrix<double>, NaturalOrdering<int>> solver_ordered, solver_unordered, solver_ordered_partial; MatrixXd omega = MatrixXd::Constant(dim, dim, 0.1) + MatrixXd::Identity(dim, dim); SparseMatrix<double> A(0,0), - A_ordered(0,0); + A_ordered(0,0), + R(0,0); VectorXd b, - b_ordered, + x, x_ordered, - x; + x_ordered_partial; int n_measurements = 0; int n_nodes = 0; // ordering variables - //SparseMatrix<int> A_nodes(0,0); SparseMatrix<int> A_nodes_ordered(0,0); PermutationMatrix<Dynamic, Dynamic, int> acc_permutation_nodes_matrix(0); @@ -117,8 +134,8 @@ int main(int argc, char *argv[]) VectorXi nodes_ordering_constraints; // results variables - clock_t t1, t2, t3, t4; - double time1=0, time2=0, time3=0, time4=0; + clock_t t_ordering, t_solving_ordered_full, t_solving_unordered, t_solving_ordered_partial, t4; + double time_ordering=0, time_solving_unordered=0, time_solving_ordered=0, time_solving_ordered_partial=0; std::cout << "STARTING INCREMENTAL QR TEST" << std::endl << std::endl; @@ -166,11 +183,12 @@ int main(int argc, char *argv[]) // Resize state x.conservativeResize(n_nodes*dim); x_ordered.conservativeResize(n_nodes*dim); + x_ordered_partial.conservativeResize(n_nodes*dim); } A.conservativeResize(n_measurements*dim,n_nodes*dim); A_ordered.conservativeResize(n_measurements*dim,n_nodes*dim); + R.conservativeResize(n_nodes*dim,n_nodes*dim); b.conservativeResize(n_measurements*dim); - //A_nodes.conservativeResize(n_measurements,n_nodes); A_nodes_ordered.conservativeResize(n_measurements,n_nodes); // ADD MEASUREMENTS @@ -182,7 +200,6 @@ int main(int argc, char *argv[]) add_sparse_block(2*omega, A, A.rows()-dim, measurement.at(j) * dim); add_sparse_block(2*omega, A_ordered, A_ordered.rows()-dim, ordered_node * dim); - //A_nodes.coeffRef(A_nodes.rows()-1, measurement.at(j)) = 1; A_nodes_ordered.coeffRef(A_nodes_ordered.rows()-1, ordered_node) = 1; b.segment(b.size() - dim, dim) = VectorXd::LinSpaced(dim, b.size()-dim, b.size()-1); @@ -192,28 +209,27 @@ int main(int argc, char *argv[]) } // std::cout << "Solving Ax = b" << std::endl; -// std::cout << "A_nodes: " << std::endl << MatrixXi::Identity(A_nodes.rows(), A_nodes.rows()) * A_nodes << std::endl << std::endl; // std::cout << "A_nodes_ordered: " << std::endl << MatrixXi::Identity(A_nodes_ordered.rows(), A_nodes_ordered.rows()) * A_nodes_ordered << std::endl << std::endl; // std::cout << "A: " << std::endl << MatrixXd::Identity(A.rows(), A.rows()) * A << std::endl << std::endl; // std::cout << "A_ordered: " << std::endl << MatrixXd::Identity(A.rows(), A.rows()) * A_ordered << std::endl << std::endl; // std::cout << "b: " << std::endl << b.transpose() << std::endl << std::endl; // BLOCK REORDERING ------------------------------------ - t1 = clock(); - int subproblem_nodes = n_nodes - min_ordered_node; - if (n_nodes > 1 && subproblem_nodes > 2) // only reordering when involved nodes in the measurement are not the two last ones + t_ordering = clock(); + int ordered_nodes = n_nodes - min_ordered_node; + int unordered_nodes = n_nodes - ordered_nodes; + if (n_nodes > 1 && ordered_nodes > 2) // only reordering when involved nodes in the measurement are not the two last ones { // SUBPROBLEM ORDERING (from first node variable to last one) std::cout << "ordering partial problem: " << min_ordered_node << " to "<< n_nodes - 1 << std::endl; - t3 = clock(); - SparseMatrix<int> sub_A_nodes_ordered = A_nodes_ordered.rightCols(subproblem_nodes); + SparseMatrix<int> sub_A_nodes_ordered = A_nodes_ordered.rightCols(ordered_nodes); // partial ordering constraints VectorXi nodes_partial_ordering_constraints = sub_A_nodes_ordered.bottomRows(1).transpose(); // computing nodes partial ordering A_nodes_ordered.makeCompressed(); - PermutationMatrix<Dynamic, Dynamic, int> partial_permutation_nodes_matrix(subproblem_nodes); + PermutationMatrix<Dynamic, Dynamic, int> partial_permutation_nodes_matrix(ordered_nodes); partial_ordering(sub_A_nodes_ordered, partial_permutation_nodes_matrix, nodes_partial_ordering_constraints.data()); // node ordering to variable ordering @@ -221,65 +237,116 @@ int main(int argc, char *argv[]) permutation_2_block_permutation(partial_permutation_nodes_matrix, partial_permutation_matrix , dim); // apply partial orderings - A_nodes_ordered.rightCols(subproblem_nodes) = (A_nodes_ordered.rightCols(subproblem_nodes) * partial_permutation_nodes_matrix.transpose()).sparseView(); - A_ordered.rightCols(subproblem_nodes * dim) = (A_ordered.rightCols(subproblem_nodes * dim) * partial_permutation_matrix.transpose()).sparseView(); + A_nodes_ordered.rightCols(ordered_nodes) = (A_nodes_ordered.rightCols(ordered_nodes) * partial_permutation_nodes_matrix.transpose()).sparseView(); + A_ordered.rightCols(ordered_nodes * dim) = (A_ordered.rightCols(ordered_nodes * dim) * partial_permutation_matrix.transpose()).sparseView(); + R.rightCols(ordered_nodes * dim) = (R.rightCols(ordered_nodes * dim) * partial_permutation_matrix.transpose()).sparseView(); // ACCUMULATING PERMUTATIONS PermutationMatrix<Dynamic, Dynamic, int> permutation_nodes_matrix(VectorXi::LinSpaced(n_nodes, 0, n_nodes - 1)); // identity permutation - permutation_nodes_matrix.indices().tail(subproblem_nodes) = partial_permutation_nodes_matrix.indices() + VectorXi::Constant(subproblem_nodes, n_nodes - subproblem_nodes); + permutation_nodes_matrix.indices().tail(ordered_nodes) = partial_permutation_nodes_matrix.indices() + VectorXi::Constant(ordered_nodes, n_nodes - ordered_nodes); acc_permutation_nodes_matrix = permutation_nodes_matrix * acc_permutation_nodes_matrix; - - time3 += ((double) clock() - t3) / CLOCKS_PER_SEC; - -// std::cout << "partial_permutation_nodes_matrix: " << std::endl << partial_permutation_nodes_matrix.indices().transpose() << std::endl << std::endl; -// std::cout << "permutation_nodes_matrix: " << std::endl << permutation_nodes_matrix.indices().transpose() << std::endl << std::endl; - - //std::cout << "A_nodes_ordered " << std::endl << MatrixXi::Identity(A_nodes_ordered.rows(), A_nodes_ordered.rows()) * A_nodes_ordered << std::endl << std::endl; - } -// std::cout << "incrementally ordered A Block structure: " << std::endl << MatrixXi::Identity(A_nodes_ordered.rows(), A_nodes_ordered.rows()) * A_nodes_ordered << std::endl << std::endl; - - //std::cout << "A: " << std::endl << MatrixXd::Identity(A.rows(), A.rows()) * A << std::endl << std::endl; - //std::cout << "ordered A: " << std::endl << MatrixXd::Identity(A.rows(), A.rows()) * A_ordered << std::endl << std::endl; + time_ordering += ((double) clock() - t_ordering) / CLOCKS_PER_SEC; + // std::cout << "incrementally ordered A Block structure: " << std::endl << MatrixXi::Identity(A_nodes_ordered.rows(), A_nodes_ordered.rows()) * A_nodes_ordered << std::endl << std::endl; + //std::cout << "ordered A: " << std::endl << MatrixXd::Identity(A_ordered.rows(), A_ordered.rows()) * A_ordered << std::endl << std::endl; //std::cout << "b: " << std::endl << b.transpose() << std::endl << std::endl; - // solving + // SOLVING + // solving ordered subproblem + t_solving_ordered_partial = clock(); A_nodes_ordered.makeCompressed(); A_ordered.makeCompressed(); - solver.compute(A_ordered); - if (solver.info() != Success) + + // finding measurements block + SparseMatrix<int> measurements_to_initial = A_nodes_ordered.col(min_ordered_node); +// std::cout << "measurements_to_initial " << measurements_to_initial << std::endl; +// std::cout << "measurements_to_initial.innerIndexPtr()[measurements_to_initial.outerIndexPtr()[0]] " << measurements_to_initial.innerIndexPtr()[measurements_to_initial.outerIndexPtr()[0]] << std::endl; + int initial_measurement = measurements_to_initial.innerIndexPtr()[measurements_to_initial.outerIndexPtr()[0]]; + + SparseMatrix<double> A_ordered_partial = A_ordered.bottomRightCorner((n_nodes - initial_measurement) * dim, ordered_nodes * dim); + solver_ordered_partial.compute(A_ordered_partial); + if (solver_ordered_partial.info() != Success) { std::cout << "decomposition failed" << std::endl; return 0; } - //std::cout << "R: " << std::endl << solver.matrixR() << std::endl; - x_ordered = solver.solve(b); + std::cout << "R new" << std::endl << MatrixXd::Identity(ordered_nodes * dim, ordered_nodes * dim) * solver_ordered_partial.matrixR() << std::endl; + x_ordered_partial.tail(ordered_nodes * dim) = solver_ordered_partial.solve(b.tail(ordered_nodes * dim)); + std::cout << "x_ordered_partial.tail(ordered_nodes * dim)" << std::endl << x_ordered_partial.tail(ordered_nodes * dim).transpose() << std::endl; + // store new part of R (equivalent to R.bottomRightCorner(ordered_nodes * dim, ordered_nodes * dim) = solver3.matrixR();) + erase_sparse_block(R, unordered_nodes * dim, unordered_nodes * dim, ordered_nodes * dim, ordered_nodes * dim); + add_sparse_block(solver_ordered_partial.matrixR(), R, unordered_nodes * dim, unordered_nodes * dim); + std::cout << "R" << std::endl << MatrixXd::Identity(R.rows(), R.rows()) * R << std::endl; + R.makeCompressed(); + + // solving not ordered subproblem + if (unordered_nodes > 0) + { + std::cout << "--------------------- solving unordered part" << std::endl; + SparseMatrix<double> R1 = R.topLeftCorner(unordered_nodes * dim, unordered_nodes * dim); + std::cout << "R1" << std::endl << MatrixXd::Identity(R1.rows(), R1.rows()) * R1 << std::endl; + SparseMatrix<double> R2 = R.topRightCorner(unordered_nodes * dim, ordered_nodes * dim); + std::cout << "R2" << std::endl << MatrixXd::Identity(R2.rows(), R2.rows()) * R2 << std::endl; + solver_ordered_partial.compute(R1); + if (solver_ordered_partial.info() != Success) + { + std::cout << "decomposition failed" << std::endl; + return 0; + } + x_ordered_partial.head(unordered_nodes * dim) = solver_ordered_partial.solve(b.head(unordered_nodes * dim) - R2 * x_ordered_partial.tail(ordered_nodes * dim)); + } + // undo ordering PermutationMatrix<Dynamic, Dynamic, int> acc_permutation_matrix(A_ordered.cols()); permutation_2_block_permutation(acc_permutation_nodes_matrix, acc_permutation_matrix , dim); + x_ordered_partial = acc_permutation_matrix.inverse() * x_ordered_partial; + time_solving_ordered_partial += ((double) clock() - t_solving_ordered_partial) / CLOCKS_PER_SEC; + + // SOLVING + // full ordered problem + t_solving_ordered_full = clock(); + A_nodes_ordered.makeCompressed(); + A_ordered.makeCompressed(); + solver_ordered.compute(A_ordered); + if (solver_ordered.info() != Success) + { + std::cout << "decomposition failed" << std::endl; + return 0; + } + x_ordered = solver_ordered.solve(b); + std::cout << "solver_ordered.matrixR()" << std::endl << MatrixXd::Identity(A_ordered.cols(), A_ordered.cols()) * solver_ordered.matrixR() << std::endl; + // undo ordering + PermutationMatrix<Dynamic, Dynamic, int> acc_permutation_matrix2(A_ordered.cols()); + permutation_2_block_permutation(acc_permutation_nodes_matrix, acc_permutation_matrix2 , dim); x_ordered = acc_permutation_matrix.inverse() * x_ordered; - time1 += ((double) clock() - t1) / CLOCKS_PER_SEC; + time_solving_ordered += ((double) clock() - t_solving_ordered_full) / CLOCKS_PER_SEC; // WITHOUT ORDERING - t2 = clock(); + t_solving_unordered = clock(); A.makeCompressed(); - solver2.compute(A); - if (solver2.info() != Success) + solver_unordered.compute(A); + if (solver_unordered.info() != Success) { std::cout << "decomposition failed" << std::endl; return 0; } - //std::cout << "no ordering? " << solver2.colsPermutation().indices().transpose() << std::endl; - x = solver2.solve(b); - time2 += ((double) clock() - t2) / CLOCKS_PER_SEC; + //std::cout << "no ordering? " << solver_unordered.colsPermutation().indices().transpose() << std::endl; + x = solver_unordered.solve(b); + std::cout << "solver_unordered.matrixR()" << std::endl << MatrixXd::Identity(A.cols(), A.cols()) * solver_unordered.matrixR() << std::endl; + time_solving_unordered += ((double) clock() - t_solving_unordered) / CLOCKS_PER_SEC; // RESULTS ------------------------------------ std::cout << "========================= RESULTS " << i << ":" << std::endl; - std::cout << "NO REORDERING: solved in " << time2*1e3 << " ms | " << solver2.matrixR().nonZeros() << " nonzeros in R"<< std::endl; - std::cout << "BLOCK REORDERING: solved in " << time1*1e3 << " ms | " << solver.matrixR().nonZeros() << " nonzeros in R"<< std::endl; - //std::cout << "x1 = " << x.transpose() << std::endl; - std::cout << "x = " << x.transpose() << std::endl; - std::cout << "x(ordering) = " << x_ordered.transpose() << std::endl; - std::cout << "x - x(ordering)= " << (x-x_ordered).transpose() << std::endl; + std::cout << "NO REORDERING: solved in " << time_solving_unordered*1e3 << " ms | " << solver_unordered.matrixR().nonZeros() << " nonzeros in R"<< std::endl; + std::cout << "BLOCK REORDERING: solved in " << time_solving_ordered*1e3 << " ms | " << solver_ordered.matrixR().nonZeros() << " nonzeros in R"<< std::endl; + std::cout << "BLOCK REORDERING 2: solved in " << time_solving_ordered_partial*1e3 << " ms | " << R.nonZeros() << " nonzeros in R"<< std::endl; + + std::cout << "x = " << x.transpose() << std::endl; + std::cout << "x_ordered = " << x_ordered.transpose() << std::endl; + std::cout << "x_ordered_partial = " << x_ordered_partial.transpose() << std::endl; + if ((x_ordered_partial-x_ordered).maxCoeff() < 1e-10) + std::cout << "Both solutions are equals (tolerance " << (x_ordered_partial-x_ordered).maxCoeff() << ")" << std::endl; + else + std::cout << "DIFFERENT SOLUTIONS!!!!!!!! max difference " << (x_ordered_partial-x_ordered).maxCoeff() << std::endl; } } -- GitLab