Test explicit iterative Schur solves

Compare explicit ITERATIVE_SCHUR solutions with dense QR through the
existing Schur test helper. Cover regularized and unregularized systems,
zero retained blocks, and varying retained block sizes.

Use SCHUR_JACOBI, NO_SPARSE, and a residual tolerance of 1e-12.

Addresses https://github.com/ceres-solver/ceres-solver/issues/290.

Codex used.

Change-Id: I3b9efdf5f2d08cc4cff66b6babdabcde822966da
diff --git a/internal/ceres/schur_complement_solver_test.cc b/internal/ceres/schur_complement_solver_test.cc
index de00508..db15185 100644
--- a/internal/ceres/schur_complement_solver_test.cc
+++ b/internal/ceres/schur_complement_solver_test.cc
@@ -78,12 +78,15 @@
 
     // Gold standard solutions using dense QR factorization.
     DenseSparseMatrix dense_A(triplet_A);
-    qr->Solve(&dense_A, b.get(), LinearSolver::PerSolveOptions(), sol.data());
+    LinearSolver::Summary summary = qr->Solve(
+        &dense_A, b.get(), LinearSolver::PerSolveOptions(), sol.data());
+    ASSERT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
     // Gold standard solution with appended diagonal.
     LinearSolver::PerSolveOptions per_solve_options;
     per_solve_options.D = D.get();
-    qr->Solve(&dense_A, b.get(), per_solve_options, sol_d.data());
+    summary = qr->Solve(&dense_A, b.get(), per_solve_options, sol_d.data());
+    ASSERT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
   }
 
   void ComputeAndCompareSolutions(
@@ -104,6 +107,9 @@
     options.sparse_linear_algebra_library_type =
         sparse_linear_algebra_library_type;
     options.ordering_type = ordering_type;
+    options.use_explicit_schur_complement = true;
+    options.preconditioner_type = SCHUR_JACOBI;
+    options.max_num_iterations = num_cols;
     ContextImpl context;
     options.context = &context;
     DetectStructure(*A->block_structure(),
@@ -115,6 +121,7 @@
     std::unique_ptr<LinearSolver> solver(LinearSolver::Create(options));
 
     LinearSolver::PerSolveOptions per_solve_options;
+    per_solve_options.r_tolerance = 1e-12;
     LinearSolver::Summary summary;
     if (regularization) {
       per_solve_options.D = D.get();
@@ -167,6 +174,25 @@
       4, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
+TEST_F(SchurComplementSolverTest, ExplicitSchurSmallProblem) {
+  ComputeAndCompareSolutions(
+      2, false, ITERATIVE_SCHUR, EIGEN, NO_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      2, true, ITERATIVE_SCHUR, EIGEN, NO_SPARSE, OrderingType::NATURAL);
+}
+
+TEST_F(SchurComplementSolverTest, ExplicitSchurLargeProblem) {
+  ComputeAndCompareSolutions(
+      3, false, ITERATIVE_SCHUR, EIGEN, NO_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      3, true, ITERATIVE_SCHUR, EIGEN, NO_SPARSE, OrderingType::NATURAL);
+}
+
+TEST_F(SchurComplementSolverTest, ExplicitSchurVaryingFBlockSize) {
+  ComputeAndCompareSolutions(
+      4, true, ITERATIVE_SCHUR, EIGEN, NO_SPARSE, OrderingType::NATURAL);
+}
+
 #ifndef CERES_NO_LAPACK
 TEST_F(SchurComplementSolverTest, DenseSchurWithLAPACKSmallProblem) {
   ComputeAndCompareSolutions(