Template specializations for PartitionedMatrixView.

This speeds up the matrix vector products in the
IterativeSchurSolver by upto 40%.

Change-Id: Ib5e8d77c7269cf5ffdd2d161893734bb6d38215d
diff --git a/internal/ceres/CMakeLists.txt b/internal/ceres/CMakeLists.txt
index 02a1731..d963fd6 100644
--- a/internal/ceres/CMakeLists.txt
+++ b/internal/ceres/CMakeLists.txt
@@ -128,7 +128,7 @@
   FILE(GLOB CERES_INTERNAL_SCHUR_FILES generated/*.cc)
 ELSE (SCHUR_SPECIALIZATIONS)
   # Only the fully dynamic solver. The build is much faster this way.
-  FILE(GLOB CERES_INTERNAL_SCHUR_FILES generated/schur_eliminator_d_d_d.cc)
+  FILE(GLOB CERES_INTERNAL_SCHUR_FILES generated/*_d_d_d.cc)
 ENDIF (SCHUR_SPECIALIZATIONS)
 
 # Primarily for Android, but optionally for others, use the minimal internal
diff --git a/internal/ceres/generate_partitioned_matrix_view_specializations.py b/internal/ceres/generate_partitioned_matrix_view_specializations.py
new file mode 100644
index 0000000..1ee8b8e
--- /dev/null
+++ b/internal/ceres/generate_partitioned_matrix_view_specializations.py
@@ -0,0 +1,226 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2013 Google Inc. All rights reserved.
+# http://code.google.com/p/ceres-solver/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+#   used to endorse or promote products derived from this software without
+#   specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: sameeragarwal@google.com (Sameer Agarwal)
+#
+# Script for explicitly generating template specialization of the
+# PartitionedMatrixView class. Explicitly generating these
+# instantiations in separate .cc files breaks the compilation into
+# separate compilation unit rather than one large cc file.
+#
+# This script creates two sets of files.
+#
+# 1. partitioned_matrix_view_x_x_x.cc
+# where, the x indicates the template parameters and
+#
+# 2. partitioned_matrix_view.cc
+#
+# that contains a factory function for instantiating these classes
+# based on runtime parameters.
+#
+# The list of tuples, specializations indicates the set of
+# specializations that is generated.
+
+# Set of template specializations to generate
+SPECIALIZATIONS = [(2, 2, 2),
+                   (2, 2, 3),
+                   (2, 2, 4),
+                   (2, 2, "Eigen::Dynamic"),
+                   (2, 3, 3),
+                   (2, 3, 4),
+                   (2, 3, 9),
+                   (2, 3, "Eigen::Dynamic"),
+                   (2, 4, 3),
+                   (2, 4, 4),
+                   (2, 4, "Eigen::Dynamic"),
+                   (2, "Eigen::Dynamic", "Eigen::Dynamic"),
+                   (4, 4, 2),
+                   (4, 4, 3),
+                   (4, 4, 4),
+                   (4, 4, "Eigen::Dynamic"),
+                   ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
+HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+"""
+
+DYNAMIC_FILE = """
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<%s, %s, %s>;
+
+}  // namespace internal
+}  // namespace ceres
+"""
+
+SPECIALIZATION_FILE = """
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<%s, %s, %s>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_FILE_HEADER = """
+#include "ceres/linear_solver.h"
+#include "ceres/partitioned_matrix_view.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+PartitionedMatrixViewBase*
+PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
+                                  const BlockSparseMatrix& matrix) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_CONDITIONAL = """  if ((options.row_block_size == %s) &&
+      (options.e_block_size == %s) &&
+      (options.f_block_size == %s)) {
+    return new PartitionedMatrixView<%s, %s, %s>(
+                 matrix, options.elimination_groups[0]);
+  }
+"""
+
+FACTORY_FOOTER = """
+#endif
+  VLOG(1) << "Template specializations not found for <"
+          << options.row_block_size << ","
+          << options.e_block_size << ","
+          << options.f_block_size << ">";
+  return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+               matrix, options.elimination_groups[0]);
+};
+
+}  // namespace internal
+}  // namespace ceres
+"""
+
+
+def SuffixForSize(size):
+  if size == "Eigen::Dynamic":
+    return "d"
+  return str(size)
+
+
+def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
+  return "_".join([prefix] + map(SuffixForSize, (row_block_size,
+                                                 e_block_size,
+                                                 f_block_size)))
+
+
+def Specialize():
+  """
+  Generate specialization code and the conditionals to instantiate it.
+  """
+  f = open("partitioned_matrix_view.cc", "w")
+  f.write(HEADER)
+  f.write(FACTORY_FILE_HEADER)
+
+  for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+    output = SpecializationFilename("generated/partitioned_matrix_view",
+                                    row_block_size,
+                                    e_block_size,
+                                    f_block_size) + ".cc"
+    fptr = open(output, "w")
+    fptr.write(HEADER)
+
+    template = SPECIALIZATION_FILE
+    if (row_block_size == "Eigen::Dynamic" and
+        e_block_size == "Eigen::Dynamic" and
+        f_block_size == "Eigen::Dynamic"):
+      template = DYNAMIC_FILE
+
+    fptr.write(template % (row_block_size, e_block_size, f_block_size))
+    fptr.close()
+
+    f.write(FACTORY_CONDITIONAL % (row_block_size,
+                                   e_block_size,
+                                   f_block_size,
+                                   row_block_size,
+                                   e_block_size,
+                                   f_block_size))
+  f.write(FACTORY_FOOTER)
+  f.close()
+
+
+if __name__ == "__main__":
+  Specialize()
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc b/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
new file mode 100644
index 0000000..3079cff
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 2>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc b/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
new file mode 100644
index 0000000..d2ea113
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 3>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc b/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
new file mode 100644
index 0000000..4e59910
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 4>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc b/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
new file mode 100644
index 0000000..8239295
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc b/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
new file mode 100644
index 0000000..b408ca5
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 3>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc b/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
new file mode 100644
index 0000000..fc468bf
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 4>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc b/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
new file mode 100644
index 0000000..3633a1c
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 9>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc b/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
new file mode 100644
index 0000000..8314727
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc b/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
new file mode 100644
index 0000000..04ebe93
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 3>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc b/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
new file mode 100644
index 0000000..5374554
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 4>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc b/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
new file mode 100644
index 0000000..69eccf9
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc b/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
new file mode 100644
index 0000000..3238812
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc b/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
new file mode 100644
index 0000000..1a223ff
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 2>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc b/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
new file mode 100644
index 0000000..d50c18d
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 3>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc b/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
new file mode 100644
index 0000000..adf7783
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 4>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc b/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
new file mode 100644
index 0000000..06f75ea
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc b/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
new file mode 100644
index 0000000..b392fd5
--- /dev/null
+++ b/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
@@ -0,0 +1,53 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2013 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/implicit_schur_complement.cc b/internal/ceres/implicit_schur_complement.cc
index 32722bb..8ab6b6d 100644
--- a/internal/ceres/implicit_schur_complement.cc
+++ b/internal/ceres/implicit_schur_complement.cc
@@ -35,21 +35,17 @@
 #include "ceres/block_structure.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
 namespace ceres {
 namespace internal {
 
-ImplicitSchurComplement::ImplicitSchurComplement(int num_eliminate_blocks,
-                                                 bool preconditioner)
-    : num_eliminate_blocks_(num_eliminate_blocks),
-      preconditioner_(preconditioner),
-      A_(NULL),
+ImplicitSchurComplement::ImplicitSchurComplement(const LinearSolver::Options& options)
+    : options_(options),
       D_(NULL),
-      b_(NULL),
-      block_diagonal_EtE_inverse_(NULL),
-      block_diagonal_FtF_inverse_(NULL) {
+      b_(NULL) {
 }
 
 ImplicitSchurComplement::~ImplicitSchurComplement() {
@@ -61,7 +57,7 @@
   // Since initialization is reasonably heavy, perhaps we can save on
   // constructing a new object everytime.
   if (A_ == NULL) {
-    A_.reset(new PartitionedMatrixView(A, num_eliminate_blocks_));
+    A_.reset(PartitionedMatrixViewBase::Create(options_, A));
   }
 
   D_ = D;
@@ -71,7 +67,7 @@
   // E'E and F'E.
   if (block_diagonal_EtE_inverse_ == NULL) {
     block_diagonal_EtE_inverse_.reset(A_->CreateBlockDiagonalEtE());
-    if (preconditioner_) {
+    if (options_.preconditioner_type == JACOBI) {
       block_diagonal_FtF_inverse_.reset(A_->CreateBlockDiagonalFtF());
     }
     rhs_.resize(A_->num_cols_f());
@@ -82,7 +78,7 @@
     tmp_f_cols_.resize(A_->num_cols_f());
   } else {
     A_->UpdateBlockDiagonalEtE(block_diagonal_EtE_inverse_.get());
-    if (preconditioner_) {
+    if (options_.preconditioner_type == JACOBI) {
       A_->UpdateBlockDiagonalFtF(block_diagonal_FtF_inverse_.get());
     }
   }
@@ -91,7 +87,7 @@
   // contributions from the diagonal D if it is non-null. Add that to
   // the block diagonals and invert them.
   AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get());
-  if (preconditioner_)  {
+  if (options_.preconditioner_type == JACOBI) {
     AddDiagonalAndInvert((D_ ==  NULL) ? NULL : D_ + A_->num_cols_e(),
                          block_diagonal_FtF_inverse_.get());
   }
diff --git a/internal/ceres/implicit_schur_complement.h b/internal/ceres/implicit_schur_complement.h
index c1bb6e1..c992bdc 100644
--- a/internal/ceres/implicit_schur_complement.h
+++ b/internal/ceres/implicit_schur_complement.h
@@ -35,6 +35,7 @@
 #define CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
 
 #include "ceres/linear_operator.h"
+#include "ceres/linear_solver.h"
 #include "ceres/partitioned_matrix_view.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/scoped_ptr.h"
@@ -96,7 +97,7 @@
   //
   // TODO(sameeragarwal): Get rid of the two bools below and replace
   // them with enums.
-  ImplicitSchurComplement(int num_eliminate_blocks, bool preconditioner);
+  ImplicitSchurComplement(const LinearSolver::Options& options);
   virtual ~ImplicitSchurComplement();
 
   // Initialize the Schur complement for a linear least squares
@@ -142,10 +143,9 @@
   void AddDiagonalAndInvert(const double* D, BlockSparseMatrix* matrix);
   void UpdateRhs();
 
-  int num_eliminate_blocks_;
-  bool preconditioner_;
+  const LinearSolver::Options& options_;
 
-  scoped_ptr<PartitionedMatrixView> A_;
+  scoped_ptr<PartitionedMatrixViewBase> A_;
   const double* D_;
   const double* b_;
 
diff --git a/internal/ceres/implicit_schur_complement_test.cc b/internal/ceres/implicit_schur_complement_test.cc
index 1694273..3369ecb 100644
--- a/internal/ceres/implicit_schur_complement_test.cc
+++ b/internal/ceres/implicit_schur_complement_test.cc
@@ -120,7 +120,10 @@
     Vector reference_solution;
     ReducedLinearSystemAndSolution(D, &lhs, &rhs, &reference_solution);
 
-    ImplicitSchurComplement isc(num_eliminate_blocks_, true);
+    LinearSolver::Options options;
+    options.elimination_groups.push_back(num_eliminate_blocks_);
+    options.preconditioner_type = JACOBI;
+    ImplicitSchurComplement isc(options);
     isc.Init(*A_, D, b_.get());
 
     int num_sc_cols = lhs.cols();
diff --git a/internal/ceres/iterative_schur_complement_solver.cc b/internal/ceres/iterative_schur_complement_solver.cc
index 1aac565..90013ff 100644
--- a/internal/ceres/iterative_schur_complement_solver.cc
+++ b/internal/ceres/iterative_schur_complement_solver.cc
@@ -38,6 +38,7 @@
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
 #include "ceres/conjugate_gradients_solver.h"
+#include "ceres/detect_structure.h"
 #include "ceres/implicit_schur_complement.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/scoped_ptr.h"
@@ -69,17 +70,20 @@
   EventLogger event_logger("IterativeSchurComplementSolver::Solve");
 
   CHECK_NOTNULL(A->block_structure());
-
+  const int num_eliminate_blocks = options_.elimination_groups[0];
   // Initialize a ImplicitSchurComplement object.
   if (schur_complement_ == NULL) {
-    schur_complement_.reset(
-        new ImplicitSchurComplement(options_.elimination_groups[0],
-                                    options_.preconditioner_type == JACOBI));
+    DetectStructure(*(A->block_structure()),
+                    num_eliminate_blocks,
+                    &options_.row_block_size,
+                    &options_.e_block_size,
+                    &options_.f_block_size);
+    schur_complement_.reset(new ImplicitSchurComplement(options_));
   }
   schur_complement_->Init(*A, per_solve_options.D, b);
 
   const int num_schur_complement_blocks =
-      A->block_structure()->cols.size() - options_.elimination_groups[0];
+      A->block_structure()->cols.size() - num_eliminate_blocks;
   if (num_schur_complement_blocks == 0) {
     VLOG(2) << "No parameter blocks left in the schur complement.";
     LinearSolver::Summary cg_summary;
@@ -90,14 +94,12 @@
   }
 
   // Initialize the solution to the Schur complement system to zero.
-  //
-  // TODO(sameeragarwal): There maybe a better initialization than an
-  // all zeros solution. Explore other cheap starting points.
   reduced_linear_system_solution_.resize(schur_complement_->num_rows());
   reduced_linear_system_solution_.setZero();
 
-  // Instantiate a conjugate gradient solver that runs on the Schur complement
-  // matrix with the block diagonal of the matrix F'F as the preconditioner.
+  // Instantiate a conjugate gradient solver that runs on the Schur
+  // complement matrix with the block diagonal of the matrix F'F as
+  // the preconditioner.
   LinearSolver::Options cg_options;
   cg_options.max_num_iterations = options_.max_num_iterations;
   ConjugateGradientsSolver cg_solver(cg_options);
diff --git a/internal/ceres/partitioned_matrix_view.cc b/internal/ceres/partitioned_matrix_view.cc
index 59eaff8..7936a40 100644
--- a/internal/ceres/partitioned_matrix_view.cc
+++ b/internal/ceres/partitioned_matrix_view.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// Copyright 2013 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,277 +27,141 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
 
-#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 10
-
+#include "ceres/linear_solver.h"
 #include "ceres/partitioned_matrix_view.h"
-
-#include <algorithm>
-#include <cstring>
-#include <vector>
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/small_blas.h"
-#include "glog/logging.h"
 
 namespace ceres {
 namespace internal {
 
-PartitionedMatrixView::PartitionedMatrixView(
-    const BlockSparseMatrix& matrix,
-    int num_col_blocks_a)
-    : matrix_(matrix),
-      num_col_blocks_e_(num_col_blocks_a) {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  CHECK_NOTNULL(bs);
-
-  num_col_blocks_f_ = bs->cols.size() - num_col_blocks_a;
-
-  // Compute the number of row blocks in E. The number of row blocks
-  // in E maybe less than the number of row blocks in the input matrix
-  // as some of the row blocks at the bottom may not have any
-  // e_blocks. For a definition of what an e_block is, please see
-  // explicit_schur_complement_solver.h
-  num_row_blocks_e_ = 0;
-  for (int r = 0; r < bs->rows.size(); ++r) {
-    const vector<Cell>& cells = bs->rows[r].cells;
-    if (cells[0].block_id < num_col_blocks_a) {
-      ++num_row_blocks_e_;
-    }
+PartitionedMatrixViewBase*
+PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
+                                  const BlockSparseMatrix& matrix) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 2) &&
+      (options.f_block_size == 2)) {
+    return new PartitionedMatrixView<2, 2, 2>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 2) &&
+      (options.f_block_size == 3)) {
+    return new PartitionedMatrixView<2, 2, 3>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 2) &&
+      (options.f_block_size == 4)) {
+    return new PartitionedMatrixView<2, 2, 4>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 2) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 3) &&
+      (options.f_block_size == 3)) {
+    return new PartitionedMatrixView<2, 3, 3>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 3) &&
+      (options.f_block_size == 4)) {
+    return new PartitionedMatrixView<2, 3, 4>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 3) &&
+      (options.f_block_size == 9)) {
+    return new PartitionedMatrixView<2, 3, 9>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 3) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == 3)) {
+    return new PartitionedMatrixView<2, 4, 3>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == 4)) {
+    return new PartitionedMatrixView<2, 4, 4>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 2) &&
+      (options.e_block_size == Eigen::Dynamic) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 4) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == 2)) {
+    return new PartitionedMatrixView<4, 4, 2>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 4) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == 3)) {
+    return new PartitionedMatrixView<4, 4, 3>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 4) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == 4)) {
+    return new PartitionedMatrixView<4, 4, 4>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == 4) &&
+      (options.e_block_size == 4) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
+  }
+  if ((options.row_block_size == Eigen::Dynamic) &&
+      (options.e_block_size == Eigen::Dynamic) &&
+      (options.f_block_size == Eigen::Dynamic)) {
+    return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+                 matrix, options.elimination_groups[0]);
   }
 
-  // Compute the number of columns in E and F.
-  num_cols_e_ = 0;
-  num_cols_f_ = 0;
-
-  for (int c = 0; c < bs->cols.size(); ++c) {
-    const Block& block = bs->cols[c];
-    if (c < num_col_blocks_a) {
-      num_cols_e_ += block.size;
-    } else {
-      num_cols_f_ += block.size;
-    }
-  }
-
-  CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
-}
-
-PartitionedMatrixView::~PartitionedMatrixView() {
-}
-
-// The next four methods don't seem to be particularly cache
-// friendly. This is an artifact of how the BlockStructure of the
-// input matrix is constructed. These methods will benefit from
-// multithreading as well as improved data layout.
-
-void PartitionedMatrixView::RightMultiplyE(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
-  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
-  // by the first cell in each row block.
-  const double* values = matrix_.values();
-  for (int r = 0; r < num_row_blocks_e_; ++r) {
-    const Cell& cell = bs->rows[r].cells[0];
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const int col_block_id = cell.block_id;
-    const int col_block_pos = bs->cols[col_block_id].position;
-    const int col_block_size = bs->cols[col_block_id].size;
-    MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-        values + cell.position, row_block_size, col_block_size,
-        x + col_block_pos,
-        y + row_block_pos);
-  }
-}
-
-void PartitionedMatrixView::RightMultiplyF(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
-  // Iterate over row blocks, and if the row block is in E, then
-  // multiply by all the cells except the first one which is of type
-  // E. If the row block is not in E (i.e its in the bottom
-  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
-  // are of type F and multiply by them all.
-  const double* values = matrix_.values();
-  for (int r = 0; r < bs->rows.size(); ++r) {
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
-      const int col_block_pos = bs->cols[col_block_id].position;
-      const int col_block_size = bs->cols[col_block_id].size;
-      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-          values + cells[c].position, row_block_size, col_block_size,
-          x + col_block_pos - num_cols_e(),
-          y + row_block_pos);
-    }
-  }
-}
-
-void PartitionedMatrixView::LeftMultiplyE(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
-  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
-  // by the first cell in each row block.
-  const double* values = matrix_.values();
-  for (int r = 0; r < num_row_blocks_e_; ++r) {
-    const Cell& cell = bs->rows[r].cells[0];
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const int col_block_id = cell.block_id;
-    const int col_block_pos = bs->cols[col_block_id].position;
-    const int col_block_size = bs->cols[col_block_id].size;
-    MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-        values + cell.position, row_block_size, col_block_size,
-        x + row_block_pos,
-        y + col_block_pos);
-  }
-}
-
-void PartitionedMatrixView::LeftMultiplyF(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
-  // Iterate over row blocks, and if the row block is in E, then
-  // multiply by all the cells except the first one which is of type
-  // E. If the row block is not in E (i.e its in the bottom
-  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
-  // are of type F and multiply by them all.
-  const double* values = matrix_.values();
-  for (int r = 0; r < bs->rows.size(); ++r) {
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
-      const int col_block_pos = bs->cols[col_block_id].position;
-      const int col_block_size = bs->cols[col_block_id].size;
-      MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-        values + cells[c].position, row_block_size, col_block_size,
-        x + row_block_pos,
-        y + col_block_pos - num_cols_e());
-    }
-  }
-}
-
-// Given a range of columns blocks of a matrix m, compute the block
-// structure of the block diagonal of the matrix m(:,
-// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
-// and return a BlockSparseMatrix with the this block structure. The
-// caller owns the result.
-BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalMatrixLayout(
-    int start_col_block, int end_col_block) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  CompressedRowBlockStructure* block_diagonal_structure =
-      new CompressedRowBlockStructure;
-
-  int block_position = 0;
-  int diagonal_cell_position = 0;
-
-  // Iterate over the column blocks, creating a new diagonal block for
-  // each column block.
-  for (int c = start_col_block; c < end_col_block; ++c) {
-    const Block& block = bs->cols[c];
-    block_diagonal_structure->cols.push_back(Block());
-    Block& diagonal_block = block_diagonal_structure->cols.back();
-    diagonal_block.size = block.size;
-    diagonal_block.position = block_position;
-
-    block_diagonal_structure->rows.push_back(CompressedRow());
-    CompressedRow& row = block_diagonal_structure->rows.back();
-    row.block = diagonal_block;
-
-    row.cells.push_back(Cell());
-    Cell& cell = row.cells.back();
-    cell.block_id = c - start_col_block;
-    cell.position = diagonal_cell_position;
-
-    block_position += block.size;
-    diagonal_cell_position += block.size * block.size;
-  }
-
-  // Build a BlockSparseMatrix with the just computed block
-  // structure.
-  return new BlockSparseMatrix(block_diagonal_structure);
-}
-
-BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalEtE() const {
-  BlockSparseMatrix* block_diagonal =
-      CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
-  UpdateBlockDiagonalEtE(block_diagonal);
-  return block_diagonal;
-}
-
-BlockSparseMatrix* PartitionedMatrixView::CreateBlockDiagonalFtF() const {
-  BlockSparseMatrix* block_diagonal =
-      CreateBlockDiagonalMatrixLayout(
-          num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
-  UpdateBlockDiagonalFtF(block_diagonal);
-  return block_diagonal;
-}
-
-// Similar to the code in RightMultiplyE, except instead of the matrix
-// vector multiply its an outer product.
-//
-//    block_diagonal = block_diagonal(E'E)
-void PartitionedMatrixView::UpdateBlockDiagonalEtE(
-    BlockSparseMatrix* block_diagonal) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  const CompressedRowBlockStructure* block_diagonal_structure =
-      block_diagonal->block_structure();
-
-  block_diagonal->SetZero();
-  const double* values = matrix_.values();
-  for (int r = 0; r < num_row_blocks_e_ ; ++r) {
-    const Cell& cell = bs->rows[r].cells[0];
-    const int row_block_size = bs->rows[r].block.size;
-    const int block_id = cell.block_id;
-    const int col_block_size = bs->cols[block_id].size;
-    const int cell_position =
-        block_diagonal_structure->rows[block_id].cells[0].position;
-
-    MatrixTransposeMatrixMultiply
-        <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
-            values + cell.position, row_block_size, col_block_size,
-            values + cell.position, row_block_size, col_block_size,
-            block_diagonal->mutable_values() + cell_position,
-            0, 0, col_block_size, col_block_size);
-  }
-}
-
-// Similar to the code in RightMultiplyF, except instead of the matrix
-// vector multiply its an outer product.
-//
-//   block_diagonal = block_diagonal(F'F)
-//
-void PartitionedMatrixView::UpdateBlockDiagonalFtF(
-    BlockSparseMatrix* block_diagonal) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  const CompressedRowBlockStructure* block_diagonal_structure =
-      block_diagonal->block_structure();
-
-  block_diagonal->SetZero();
-  const double* values = matrix_.values();
-  for (int r = 0; r < bs->rows.size(); ++r) {
-    const int row_block_size = bs->rows[r].block.size;
-    const vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = (r < num_row_blocks_e_) ? 1 : 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
-      const int col_block_size = bs->cols[col_block_id].size;
-      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
-      const int cell_position =
-          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
-
-      MatrixTransposeMatrixMultiply
-          <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
-              values + cells[c].position, row_block_size, col_block_size,
-              values + cells[c].position, row_block_size, col_block_size,
-              block_diagonal->mutable_values() + cell_position,
-              0, 0, col_block_size, col_block_size);
-    }
-  }
-}
+#endif
+  VLOG(1) << "Template specializations not found for <"
+          << options.row_block_size << ","
+          << options.e_block_size << ","
+          << options.f_block_size << ">";
+  return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+               matrix, options.elimination_groups[0]);
+};
 
 }  // namespace internal
 }  // namespace ceres
diff --git a/internal/ceres/partitioned_matrix_view.h b/internal/ceres/partitioned_matrix_view.h
index ebfbe40..98423a0 100644
--- a/internal/ceres/partitioned_matrix_view.h
+++ b/internal/ceres/partitioned_matrix_view.h
@@ -36,7 +36,15 @@
 #ifndef CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
 #define CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
 
-#include "ceres/block_sparse_matrix.h"
+#include <algorithm>
+#include <cstring>
+#include <vector>
+
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "ceres/small_blas.h"
+#include "glog/logging.h"
 
 namespace ceres {
 namespace internal {
@@ -51,57 +59,78 @@
 // block structure of the matrix does not satisfy the requirements of
 // the Schur complement solver it will result in unpredictable and
 // wrong output.
-//
-// This class lives in the internal name space as its a utility class
-// to be used by the IterativeSchurComplementSolver class, found in
-// iterative_schur_complement_solver.h, and is not meant for general
-// consumption.
-class PartitionedMatrixView {
+class PartitionedMatrixViewBase {
  public:
-  // matrix = [E F], where the matrix E contains the first
-  // num_col_blocks_a column blocks.
-  PartitionedMatrixView(const BlockSparseMatrix& matrix,
-                        int num_col_blocks_a);
-  ~PartitionedMatrixView();
+  virtual ~PartitionedMatrixViewBase() {}
 
   // y += E'x
-  void LeftMultiplyE(const double* x, double* y) const;
+  virtual void LeftMultiplyE(const double* x, double* y) const = 0;
 
   // y += F'x
-  void LeftMultiplyF(const double* x, double* y) const;
+  virtual void LeftMultiplyF(const double* x, double* y) const = 0;
 
   // y += Ex
-  void RightMultiplyE(const double* x, double* y) const;
+  virtual void RightMultiplyE(const double* x, double* y) const = 0;
 
   // y += Fx
-  void RightMultiplyF(const double* x, double* y) const;
+  virtual void RightMultiplyF(const double* x, double* y) const = 0;
 
   // Create and return the block diagonal of the matrix E'E.
-  BlockSparseMatrix* CreateBlockDiagonalEtE() const;
+  virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const = 0;
 
-  // Create and return the block diagonal of the matrix F'F.
-  BlockSparseMatrix* CreateBlockDiagonalFtF() const;
+  // Create and return the block diagonal of the matrix F'F. Caller
+  // owns the result.
+  virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const = 0;
 
   // Compute the block diagonal of the matrix E'E and store it in
   // block_diagonal. The matrix block_diagonal is expected to have a
   // BlockStructure (preferably created using
   // CreateBlockDiagonalMatrixEtE) which is has the same structure as
   // the block diagonal of E'E.
-  void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const;
+  virtual void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const = 0;
 
   // Compute the block diagonal of the matrix F'F and store it in
   // block_diagonal. The matrix block_diagonal is expected to have a
   // BlockStructure (preferably created using
   // CreateBlockDiagonalMatrixFtF) which is has the same structure as
   // the block diagonal of F'F.
-  void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const;
+  virtual void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const = 0;
 
-  int num_col_blocks_e() const { return num_col_blocks_e_;  }
-  int num_col_blocks_f() const { return num_col_blocks_f_;  }
-  int num_cols_e()       const { return num_cols_e_;        }
-  int num_cols_f()       const { return num_cols_f_;        }
-  int num_rows()         const { return matrix_.num_rows(); }
-  int num_cols()         const { return matrix_.num_cols(); }
+  virtual int num_col_blocks_e() const = 0;
+  virtual int num_col_blocks_f() const = 0;
+  virtual int num_cols_e()       const = 0;
+  virtual int num_cols_f()       const = 0;
+  virtual int num_rows()         const = 0;
+  virtual int num_cols()         const = 0;
+
+  static PartitionedMatrixViewBase* Create(const LinearSolver::Options& options,
+                                           const BlockSparseMatrix& matrix);
+};
+
+template <int kRowBlockSize = Eigen::Dynamic,
+          int kEBlockSize = Eigen::Dynamic,
+          int kFBlockSize = Eigen::Dynamic >
+class PartitionedMatrixView : public PartitionedMatrixViewBase {
+ public:
+  // matrix = [E F], where the matrix E contains the first
+  // num_col_blocks_a column blocks.
+  PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e);
+
+  virtual ~PartitionedMatrixView();
+  virtual void LeftMultiplyE(const double* x, double* y) const;
+  virtual void LeftMultiplyF(const double* x, double* y) const;
+  virtual void RightMultiplyE(const double* x, double* y) const;
+  virtual void RightMultiplyF(const double* x, double* y) const;
+  virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const;
+  virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const;
+  virtual void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const;
+  virtual void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const;
+  virtual int num_col_blocks_e() const { return num_col_blocks_e_;  }
+  virtual int num_col_blocks_f() const { return num_col_blocks_f_;  }
+  virtual int num_cols_e()       const { return num_cols_e_;        }
+  virtual int num_cols_f()       const { return num_cols_f_;        }
+  virtual int num_rows()         const { return matrix_.num_rows(); }
+  virtual int num_cols()         const { return matrix_.num_cols(); }
 
  private:
   BlockSparseMatrix* CreateBlockDiagonalMatrixLayout(int start_col_block,
diff --git a/internal/ceres/partitioned_matrix_view_impl.h b/internal/ceres/partitioned_matrix_view_impl.h
new file mode 100644
index 0000000..5fd5fe1
--- /dev/null
+++ b/internal/ceres/partitioned_matrix_view_impl.h
@@ -0,0 +1,379 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/partitioned_matrix_view.h"
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/small_blas.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+PartitionedMatrixView(
+    const BlockSparseMatrix& matrix,
+    int num_col_blocks_e)
+    : matrix_(matrix),
+      num_col_blocks_e_(num_col_blocks_e) {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+  CHECK_NOTNULL(bs);
+
+  num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
+
+  // Compute the number of row blocks in E. The number of row blocks
+  // in E maybe less than the number of row blocks in the input matrix
+  // as some of the row blocks at the bottom may not have any
+  // e_blocks. For a definition of what an e_block is, please see
+  // explicit_schur_complement_solver.h
+  num_row_blocks_e_ = 0;
+  for (int r = 0; r < bs->rows.size(); ++r) {
+    const vector<Cell>& cells = bs->rows[r].cells;
+    if (cells[0].block_id < num_col_blocks_e_) {
+      ++num_row_blocks_e_;
+    }
+  }
+
+  // Compute the number of columns in E and F.
+  num_cols_e_ = 0;
+  num_cols_f_ = 0;
+
+  for (int c = 0; c < bs->cols.size(); ++c) {
+    const Block& block = bs->cols[c];
+    if (c < num_col_blocks_e_) {
+      num_cols_e_ += block.size;
+    } else {
+      num_cols_f_ += block.size;
+    }
+  }
+
+  CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+~PartitionedMatrixView() {
+}
+
+// The next four methods don't seem to be particularly cache
+// friendly. This is an artifact of how the BlockStructure of the
+// input matrix is constructed. These methods will benefit from
+// multithreading as well as improved data layout.
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+RightMultiplyE(const double* x, double* y) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
+  // by the first cell in each row block.
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_; ++r) {
+    const Cell& cell = bs->rows[r].cells[0];
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const int col_block_id = cell.block_id;
+    const int col_block_pos = bs->cols[col_block_id].position;
+    const int col_block_size = bs->cols[col_block_id].size;
+    MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+        values + cell.position, row_block_size, col_block_size,
+        x + col_block_pos,
+        y + row_block_pos);
+  }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+RightMultiplyF(const double* x, double* y) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+  // Iterate over row blocks, and if the row block is in E, then
+  // multiply by all the cells except the first one which is of type
+  // E. If the row block is not in E (i.e its in the bottom
+  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
+  // are of type F and multiply by them all.
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_; ++r) {
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 1; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_pos = bs->cols[col_block_id].position;
+      const int col_block_size = bs->cols[col_block_id].size;
+      MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+          values + cells[c].position, row_block_size, col_block_size,
+          x + col_block_pos - num_cols_e_,
+          y + row_block_pos);
+    }
+  }
+
+  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 0; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_pos = bs->cols[col_block_id].position;
+      const int col_block_size = bs->cols[col_block_id].size;
+      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+          values + cells[c].position, row_block_size, col_block_size,
+          x + col_block_pos - num_cols_e_,
+          y + row_block_pos);
+    }
+  }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+LeftMultiplyE(const double* x, double* y) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+  // Iterate over the first num_row_blocks_e_ row blocks, and multiply
+  // by the first cell in each row block.
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_; ++r) {
+    const Cell& cell = bs->rows[r].cells[0];
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const int col_block_id = cell.block_id;
+    const int col_block_pos = bs->cols[col_block_id].position;
+    const int col_block_size = bs->cols[col_block_id].size;
+    MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+        values + cell.position, row_block_size, col_block_size,
+        x + row_block_pos,
+        y + col_block_pos);
+  }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+LeftMultiplyF(const double* x, double* y) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+  // Iterate over row blocks, and if the row block is in E, then
+  // multiply by all the cells except the first one which is of type
+  // E. If the row block is not in E (i.e its in the bottom
+  // num_row_blocks - num_row_blocks_e row blocks), then all the cells
+  // are of type F and multiply by them all.
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_; ++r) {
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 1; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_pos = bs->cols[col_block_id].position;
+      const int col_block_size = bs->cols[col_block_id].size;
+      MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+        values + cells[c].position, row_block_size, col_block_size,
+        x + row_block_pos,
+        y + col_block_pos - num_cols_e_);
+    }
+  }
+
+  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+    const int row_block_pos = bs->rows[r].block.position;
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 0; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_pos = bs->cols[col_block_id].position;
+      const int col_block_size = bs->cols[col_block_id].size;
+      MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+        values + cells[c].position, row_block_size, col_block_size,
+        x + row_block_pos,
+        y + col_block_pos - num_cols_e_);
+    }
+  }
+}
+
+// Given a range of columns blocks of a matrix m, compute the block
+// structure of the block diagonal of the matrix m(:,
+// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
+// and return a BlockSparseMatrix with the this block structure. The
+// caller owns the result.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix*
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalMatrixLayout(int start_col_block, int end_col_block) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+  CompressedRowBlockStructure* block_diagonal_structure =
+      new CompressedRowBlockStructure;
+
+  int block_position = 0;
+  int diagonal_cell_position = 0;
+
+  // Iterate over the column blocks, creating a new diagonal block for
+  // each column block.
+  for (int c = start_col_block; c < end_col_block; ++c) {
+    const Block& block = bs->cols[c];
+    block_diagonal_structure->cols.push_back(Block());
+    Block& diagonal_block = block_diagonal_structure->cols.back();
+    diagonal_block.size = block.size;
+    diagonal_block.position = block_position;
+
+    block_diagonal_structure->rows.push_back(CompressedRow());
+    CompressedRow& row = block_diagonal_structure->rows.back();
+    row.block = diagonal_block;
+
+    row.cells.push_back(Cell());
+    Cell& cell = row.cells.back();
+    cell.block_id = c - start_col_block;
+    cell.position = diagonal_cell_position;
+
+    block_position += block.size;
+    diagonal_cell_position += block.size * block.size;
+  }
+
+  // Build a BlockSparseMatrix with the just computed block
+  // structure.
+  return new BlockSparseMatrix(block_diagonal_structure);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix*
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalEtE() const {
+  BlockSparseMatrix* block_diagonal =
+      CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
+  UpdateBlockDiagonalEtE(block_diagonal);
+  return block_diagonal;
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix* PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalFtF() const {
+  BlockSparseMatrix* block_diagonal =
+      CreateBlockDiagonalMatrixLayout(
+          num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
+  UpdateBlockDiagonalFtF(block_diagonal);
+  return block_diagonal;
+}
+
+// Similar to the code in RightMultiplyE, except instead of the matrix
+// vector multiply its an outer product.
+//
+//    block_diagonal = block_diagonal(E'E)
+//
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+UpdateBlockDiagonalEtE(
+    BlockSparseMatrix* block_diagonal) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+  const CompressedRowBlockStructure* block_diagonal_structure =
+      block_diagonal->block_structure();
+
+  block_diagonal->SetZero();
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_ ; ++r) {
+    const Cell& cell = bs->rows[r].cells[0];
+    const int row_block_size = bs->rows[r].block.size;
+    const int block_id = cell.block_id;
+    const int col_block_size = bs->cols[block_id].size;
+    const int cell_position =
+        block_diagonal_structure->rows[block_id].cells[0].position;
+
+    MatrixTransposeMatrixMultiply
+        <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
+            values + cell.position, row_block_size, col_block_size,
+            values + cell.position, row_block_size, col_block_size,
+            block_diagonal->mutable_values() + cell_position,
+            0, 0, col_block_size, col_block_size);
+  }
+}
+
+// Similar to the code in RightMultiplyF, except instead of the matrix
+// vector multiply its an outer product.
+//
+//   block_diagonal = block_diagonal(F'F)
+//
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+  const CompressedRowBlockStructure* block_diagonal_structure =
+      block_diagonal->block_structure();
+
+  block_diagonal->SetZero();
+  const double* values = matrix_.values();
+  for (int r = 0; r < num_row_blocks_e_; ++r) {
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 1; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_size = bs->cols[col_block_id].size;
+      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
+      const int cell_position =
+          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
+
+      MatrixTransposeMatrixMultiply
+          <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
+              values + cells[c].position, row_block_size, col_block_size,
+              values + cells[c].position, row_block_size, col_block_size,
+              block_diagonal->mutable_values() + cell_position,
+              0, 0, col_block_size, col_block_size);
+    }
+  }
+
+  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+    const int row_block_size = bs->rows[r].block.size;
+    const vector<Cell>& cells = bs->rows[r].cells;
+    for (int c = 0; c < cells.size(); ++c) {
+      const int col_block_id = cells[c].block_id;
+      const int col_block_size = bs->cols[col_block_id].size;
+      const int diagonal_block_id = col_block_id - num_col_blocks_e_;
+      const int cell_position =
+          block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
+
+      MatrixTransposeMatrixMultiply
+          <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
+              values + cells[c].position, row_block_size, col_block_size,
+              values + cells[c].position, row_block_size, col_block_size,
+              block_diagonal->mutable_values() + cell_position,
+              0, 0, col_block_size, col_block_size);
+    }
+  }
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/internal/ceres/partitioned_matrix_view_test.cc b/internal/ceres/partitioned_matrix_view_test.cc
index 48f7d24..ef5dae9 100644
--- a/internal/ceres/partitioned_matrix_view_test.cc
+++ b/internal/ceres/partitioned_matrix_view_test.cc
@@ -49,6 +49,7 @@
 class PartitionedMatrixViewTest : public ::testing::Test {
  protected :
   virtual void SetUp() {
+    srand(5);
     scoped_ptr<LinearLeastSquaresProblem> problem(
         CreateLinearLeastSquaresProblemFromId(2));
     CHECK_NOTNULL(problem.get());
@@ -57,108 +58,93 @@
     num_cols_ = A_->num_cols();
     num_rows_ = A_->num_rows();
     num_eliminate_blocks_ = problem->num_eliminate_blocks;
+    LinearSolver::Options options;
+    options.elimination_groups.push_back(num_eliminate_blocks_);
+    pmv_.reset(PartitionedMatrixViewBase::Create(
+                   options,
+                   *down_cast<BlockSparseMatrix*>(A_.get())));
   }
 
   int num_rows_;
   int num_cols_;
   int num_eliminate_blocks_;
-
   scoped_ptr<SparseMatrix> A_;
+  scoped_ptr<PartitionedMatrixViewBase> pmv_;
 };
 
 TEST_F(PartitionedMatrixViewTest, DimensionsTest) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
-  EXPECT_EQ(m.num_col_blocks_e(), num_eliminate_blocks_);
-  EXPECT_EQ(m.num_col_blocks_f(), num_cols_ - num_eliminate_blocks_);
-  EXPECT_EQ(m.num_cols_e(), num_eliminate_blocks_);
-  EXPECT_EQ(m.num_cols_f(), num_cols_ - num_eliminate_blocks_);
-  EXPECT_EQ(m.num_cols(), A_->num_cols());
-  EXPECT_EQ(m.num_rows(), A_->num_rows());
+  EXPECT_EQ(pmv_->num_col_blocks_e(), num_eliminate_blocks_);
+  EXPECT_EQ(pmv_->num_col_blocks_f(), num_cols_ - num_eliminate_blocks_);
+  EXPECT_EQ(pmv_->num_cols_e(), num_eliminate_blocks_);
+  EXPECT_EQ(pmv_->num_cols_f(), num_cols_ - num_eliminate_blocks_);
+  EXPECT_EQ(pmv_->num_cols(), A_->num_cols());
+  EXPECT_EQ(pmv_->num_rows(), A_->num_rows());
 }
 
 TEST_F(PartitionedMatrixViewTest, RightMultiplyE) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
-
-  srand(5);
-
-  Vector x1(m.num_cols_e());
-  Vector x2(m.num_cols());
+  Vector x1(pmv_->num_cols_e());
+  Vector x2(pmv_->num_cols());
   x2.setZero();
 
-  for (int i = 0; i < m.num_cols_e(); ++i) {
+  for (int i = 0; i < pmv_->num_cols_e(); ++i) {
     x1(i) = x2(i) = RandDouble();
   }
 
-  Vector y1 = Vector::Zero(m.num_rows());
-  m.RightMultiplyE(x1.data(), y1.data());
+  Vector y1 = Vector::Zero(pmv_->num_rows());
+  pmv_->RightMultiplyE(x1.data(), y1.data());
 
-  Vector y2 = Vector::Zero(m.num_rows());
+  Vector y2 = Vector::Zero(pmv_->num_rows());
   A_->RightMultiply(x2.data(), y2.data());
 
-  for (int i = 0; i < m.num_rows(); ++i) {
+  for (int i = 0; i < pmv_->num_rows(); ++i) {
     EXPECT_NEAR(y1(i), y2(i), kEpsilon);
   }
 }
 
 TEST_F(PartitionedMatrixViewTest, RightMultiplyF) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
+  Vector x1(pmv_->num_cols_f());
+  Vector x2 = Vector::Zero(pmv_->num_cols());
 
-  srand(5);
-
-  Vector x1(m.num_cols_f());
-  Vector x2 = Vector::Zero(m.num_cols());
-
-  for (int i = 0; i < m.num_cols_f(); ++i) {
+  for (int i = 0; i < pmv_->num_cols_f(); ++i) {
     x1(i) = RandDouble();
-    x2(i + m.num_cols_e()) = x1(i);
+    x2(i + pmv_->num_cols_e()) = x1(i);
   }
 
-  Vector y1 = Vector::Zero(m.num_rows());
-  m.RightMultiplyF(x1.data(), y1.data());
+  Vector y1 = Vector::Zero(pmv_->num_rows());
+  pmv_->RightMultiplyF(x1.data(), y1.data());
 
-  Vector y2 = Vector::Zero(m.num_rows());
+  Vector y2 = Vector::Zero(pmv_->num_rows());
   A_->RightMultiply(x2.data(), y2.data());
 
-  for (int i = 0; i < m.num_rows(); ++i) {
+  for (int i = 0; i < pmv_->num_rows(); ++i) {
     EXPECT_NEAR(y1(i), y2(i), kEpsilon);
   }
 }
 
 TEST_F(PartitionedMatrixViewTest, LeftMultiply) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
-
-  srand(5);
-
-  Vector x = Vector::Zero(m.num_rows());
-  for (int i = 0; i < m.num_rows(); ++i) {
+  Vector x = Vector::Zero(pmv_->num_rows());
+  for (int i = 0; i < pmv_->num_rows(); ++i) {
     x(i) = RandDouble();
   }
 
-  Vector y = Vector::Zero(m.num_cols());
-  Vector y1 = Vector::Zero(m.num_cols_e());
-  Vector y2 = Vector::Zero(m.num_cols_f());
+  Vector y = Vector::Zero(pmv_->num_cols());
+  Vector y1 = Vector::Zero(pmv_->num_cols_e());
+  Vector y2 = Vector::Zero(pmv_->num_cols_f());
 
   A_->LeftMultiply(x.data(), y.data());
-  m.LeftMultiplyE(x.data(), y1.data());
-  m.LeftMultiplyF(x.data(), y2.data());
+  pmv_->LeftMultiplyE(x.data(), y1.data());
+  pmv_->LeftMultiplyF(x.data(), y2.data());
 
-  for (int i = 0; i < m.num_cols(); ++i) {
+  for (int i = 0; i < pmv_->num_cols(); ++i) {
     EXPECT_NEAR(y(i),
-                (i < m.num_cols_e()) ? y1(i) : y2(i - m.num_cols_e()),
+                (i < pmv_->num_cols_e()) ? y1(i) : y2(i - pmv_->num_cols_e()),
                 kEpsilon);
   }
 }
 
 TEST_F(PartitionedMatrixViewTest, BlockDiagonalEtE) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
-
   scoped_ptr<BlockSparseMatrix>
-      block_diagonal_ee(m.CreateBlockDiagonalEtE());
+      block_diagonal_ee(pmv_->CreateBlockDiagonalEtE());
   const CompressedRowBlockStructure* bs  = block_diagonal_ee->block_structure();
 
   EXPECT_EQ(block_diagonal_ee->num_rows(), 2);
@@ -171,11 +157,8 @@
 }
 
 TEST_F(PartitionedMatrixViewTest, BlockDiagonalFtF) {
-  PartitionedMatrixView m(*down_cast<BlockSparseMatrix*>(A_.get()),
-                          num_eliminate_blocks_);
-
   scoped_ptr<BlockSparseMatrix>
-      block_diagonal_ff(m.CreateBlockDiagonalFtF());
+      block_diagonal_ff(pmv_->CreateBlockDiagonalFtF());
   const CompressedRowBlockStructure* bs  = block_diagonal_ff->block_structure();
 
   EXPECT_EQ(block_diagonal_ff->num_rows(), 3);
diff --git a/internal/ceres/schur_jacobi_preconditioner.cc b/internal/ceres/schur_jacobi_preconditioner.cc
index 5b87e9f..46e6d02 100644
--- a/internal/ceres/schur_jacobi_preconditioner.cc
+++ b/internal/ceres/schur_jacobi_preconditioner.cc
@@ -36,7 +36,6 @@
 #include "ceres/block_random_access_diagonal_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/collections_port.h"
-#include "ceres/detect_structure.h"
 #include "ceres/internal/scoped_ptr.h"
 #include "ceres/linear_solver.h"
 #include "ceres/schur_eliminator.h"
@@ -71,18 +70,14 @@
 // Initialize the SchurEliminator.
 void SchurJacobiPreconditioner::InitEliminator(
     const CompressedRowBlockStructure& bs) {
-  LinearSolver::Options eliminator_options;
-
+    LinearSolver::Options eliminator_options;
   eliminator_options.elimination_groups = options_.elimination_groups;
   eliminator_options.num_threads = options_.num_threads;
-
-  DetectStructure(bs, options_.elimination_groups[0],
-                  &eliminator_options.row_block_size,
-                  &eliminator_options.e_block_size,
-                  &eliminator_options.f_block_size);
-
+  eliminator_options.e_block_size = options_.e_block_size;
+  eliminator_options.f_block_size = options_.f_block_size;
+  eliminator_options.row_block_size = options_.row_block_size;
   eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
-  eliminator_->Init(options_.elimination_groups[0], &bs);
+  eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
 }
 
 // Update the values of the preconditioner matrix and factorize it.
diff --git a/internal/ceres/visibility_based_preconditioner.cc b/internal/ceres/visibility_based_preconditioner.cc
index 7af1339..6535b42 100644
--- a/internal/ceres/visibility_based_preconditioner.cc
+++ b/internal/ceres/visibility_based_preconditioner.cc
@@ -43,7 +43,6 @@
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/canonical_views_clustering.h"
 #include "ceres/collections_port.h"
-#include "ceres/detect_structure.h"
 #include "ceres/graph.h"
 #include "ceres/graph_algorithms.h"
 #include "ceres/internal/scoped_ptr.h"
@@ -313,14 +312,11 @@
   LinearSolver::Options eliminator_options;
   eliminator_options.elimination_groups = options_.elimination_groups;
   eliminator_options.num_threads = options_.num_threads;
-
-  DetectStructure(bs, options_.elimination_groups[0],
-                  &eliminator_options.row_block_size,
-                  &eliminator_options.e_block_size,
-                  &eliminator_options.f_block_size);
-
+  eliminator_options.e_block_size = options_.e_block_size;
+  eliminator_options.f_block_size = options_.f_block_size;
+  eliminator_options.row_block_size = options_.row_block_size;
   eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
-  eliminator_->Init(options_.elimination_groups[0], &bs);
+  eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
 }
 
 // Update the values of the preconditioner matrix and factorize it.
diff --git a/jni/Android.mk b/jni/Android.mk
index c68f79b..3f37f35 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -63,8 +63,7 @@
 #
 #   -DCERES_RESTRICT_SCHUR_SPECIALIZATION
 #
-# to the LOCAL_CFLAGS variable below, and commenting out all the
-# generated/schur_eliminator_2_2_2.cc-alike files, leaving only the _d_d_d one.
+# to the LOCAL_CFLAGS variable below.
 #
 # Similarly if you do not need the line search minimizer, consider adding
 #
@@ -195,7 +194,23 @@
                    $(CERES_SRC_PATH)/generated/schur_eliminator_4_4_2.cc \
                    $(CERES_SRC_PATH)/generated/schur_eliminator_4_4_3.cc \
                    $(CERES_SRC_PATH)/generated/schur_eliminator_4_4_4.cc \
-                   $(CERES_SRC_PATH)/generated/schur_eliminator_4_4_d.cc
+                   $(CERES_SRC_PATH)/generated/schur_eliminator_4_4_d.cc \
+		   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_d_d_d.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_2_2.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_2_3.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_2_4.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_2_d.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_3_3.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_3_4.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_3_9.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_3_d.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_4_3.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_4_4.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_2_4_d.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_4_4_2.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_4_4_3.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_4_4_4.cc \
+                   $(CERES_SRC_PATH)/generated/partitioned_matrix_view_4_4_d.cc
 
 ifndef CERES_GLOG_DIR
 LOCAL_SRC_FILES += $(CERES_SRC_PATH)/miniglog/glog/logging.cc