Camera tracking integration
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 7 Jul 2011 17:58:33 +0000 (17:58 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 7 Jul 2011 17:58:33 +0000 (17:58 +0000)
===========================

- ColaMD moved from OpenNL to extern/.
  It'll be needed for libmv. Also, it's a bit updated from
  year 1999 to 2007.
  Need to be tested for regressions.
- Updated bundling script for libmv. Now it uses fuller
  subset of this library.
- Bundled new libmv.
- Request from Keir: add command line argument to toggle logging
  stuff on. Currently, if Blender is launched with -d argument
  libmv would start printing logging messages. There's no
  argument to increase verbosity, but there's API in libmv-capi,
  so it'll be easy to add.
- Finally fixed crash when ibuf is acquiring with user=NULL.
- Added ActiveClip property to the scene. This clip is used
  as default value for new match-moving constraints.
- Added some flags to Display panel of View3D. Related on
  displaying match-moving stuff.
- Internal change: bundles data moved inside to MovieTrackingTrack.
- Initial implementation of 3d reconstruction.
- Added constraint "Camera Solver". This constraint is supposed
  to be used to make camera follow the reconstructed camera path.
- Added "reference" property to "Follow Track" constraint.
  Now object could be "parented" to 2D track position or to
  3D bundle position.

The very quick guide:

To use reconstruction you should have footage with tracked markers,
choose two keyframes in "Tracking settings" panel. There should be
quite noticeable parallax effect between this two frames. This
is used to initialize reconstruction stuff.
Camera data (focal length and optical center) should be filled in
"Camera Data" panel. Optical center is often the center of image,
so it'll be filled in automatically.
You should also set values for undistortion (K1, K2 and K3). Currently,
there's no any visualization for this parameters and approach of
"change value -> reconstruct -> see what've changed" is the only way
for now.
Libmv team is working on auto-calibration tool, so it should be
easier to gather this coefficients in nearest (i hope) future.
There's also no scene orientation stuff.

Basic workflow:
- Open footage.
- Set markers and track them.
- Fill in camera data and keyframes.
- Hit "Solve Camera" button.
- Add "Camera Solver" constraint to camera in scene.
- Choose movieclip in that constraint.
- To see bundles in 3D viewport active clip should be set
  in scene buttons.

159 files changed:
build_files/scons/tools/Blender.py
extern/CMakeLists.txt
extern/SConscript
extern/colamd/CMakeLists.txt [new file with mode: 0644]
extern/colamd/Doc/ChangeLog [new file with mode: 0644]
extern/colamd/Doc/lesser.txt [new file with mode: 0644]
extern/colamd/Include/UFconfig.h [new file with mode: 0644]
extern/colamd/Include/colamd.h [new file with mode: 0644]
extern/colamd/README.txt [new file with mode: 0644]
extern/colamd/SConscript [new file with mode: 0644]
extern/colamd/Source/colamd.c [new file with mode: 0644]
extern/colamd/Source/colamd_global.c [new file with mode: 0644]
extern/libmv/CMakeLists.txt
extern/libmv/ChangeLog [new file with mode: 0644]
extern/libmv/SConscript
extern/libmv/bundle.sh
extern/libmv/files.txt
extern/libmv/libmv-capi.cpp
extern/libmv/libmv-capi.h
extern/libmv/libmv/base/vector.h
extern/libmv/libmv/image/image.h
extern/libmv/libmv/logging/logging.h
extern/libmv/libmv/multiview/conditioning.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/conditioning.h [new file with mode: 0644]
extern/libmv/libmv/multiview/euclidean_resection.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/euclidean_resection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/fundamental.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/fundamental.h [new file with mode: 0644]
extern/libmv/libmv/multiview/nviewtriangulation.h [new file with mode: 0644]
extern/libmv/libmv/multiview/projection.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/projection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/resection.h [new file with mode: 0644]
extern/libmv/libmv/multiview/triangulation.cc [new file with mode: 0644]
extern/libmv/libmv/multiview/triangulation.h [new file with mode: 0644]
extern/libmv/libmv/numeric/levenberg_marquardt.h
extern/libmv/libmv/simple_pipeline/bundle.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/bundle.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/camera_intrinsics.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/intersect.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/intersect.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/pipeline.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/pipeline.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/reconstruction.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/reconstruction.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/resect.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/resect.h [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/tracks.cc [new file with mode: 0644]
extern/libmv/libmv/simple_pipeline/tracks.h [new file with mode: 0644]
extern/libmv/mkfiles.sh
extern/libmv/patches/series [new file with mode: 0644]
extern/libmv/third_party/gflags/README.libmv [new file with mode: 0644]
extern/libmv/third_party/gflags/config.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_completions.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_completions.h [new file with mode: 0644]
extern/libmv/third_party/gflags/gflags_reporting.cc [new file with mode: 0644]
extern/libmv/third_party/gflags/mutex.h [new file with mode: 0644]
extern/libmv/third_party/glog/AUTHORS [new file with mode: 0644]
extern/libmv/third_party/glog/COPYING [new file with mode: 0644]
extern/libmv/third_party/glog/ChangeLog [new file with mode: 0644]
extern/libmv/third_party/glog/NEWS [new file with mode: 0644]
extern/libmv/third_party/glog/README [new file with mode: 0644]
extern/libmv/third_party/glog/README.libmv [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/commandlineflags.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/googleinit.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/base/mutex.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config_linux.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/config_mac.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/demangle.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/demangle.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/log_severity.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/raw_logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/glog/vlog_is_on.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/logging.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/raw_logging.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/signalhandler.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_generic-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_x86-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/symbolize.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/symbolize.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/utilities.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/utilities.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/vlog_is_on.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/config.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/log_severity.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/raw_logging.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/port.cc [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/port.h [new file with mode: 0644]
extern/libmv/third_party/glog/src/windows/preprocess.sh [new file with mode: 0755]
extern/libmv/third_party/ldl/CMakeLists.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Doc/ChangeLog [new file with mode: 0644]
extern/libmv/third_party/ldl/Doc/lesser.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Include/ldl.h [new file with mode: 0644]
extern/libmv/third_party/ldl/README.libmv [new file with mode: 0644]
extern/libmv/third_party/ldl/README.txt [new file with mode: 0644]
extern/libmv/third_party/ldl/Source/ldl.c [new file with mode: 0644]
extern/libmv/third_party/msinttypes/README.libmv [new file with mode: 0644]
extern/libmv/third_party/msinttypes/inttypes.h [new file with mode: 0644]
extern/libmv/third_party/msinttypes/stdint.h [new file with mode: 0644]
extern/libmv/third_party/ssba/COPYING.TXT [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_distortion.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp [new file with mode: 0644]
extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_linear.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_linear_utils.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_mathutilities.h [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_optimization.cpp [new file with mode: 0644]
extern/libmv/third_party/ssba/Math/v3d_optimization.h [new file with mode: 0644]
extern/libmv/third_party/ssba/README.TXT [new file with mode: 0644]
extern/libmv/third_party/ssba/README.libmv [new file with mode: 0755]
intern/opennl/CMakeLists.txt
intern/opennl/SConscript
intern/opennl/superlu/colamd.c [deleted file]
intern/opennl/superlu/colamd.h [deleted file]
intern/opennl/superlu/get_perm_c.c
release/scripts/startup/bl_ui/properties_object_constraint.py
release/scripts/startup/bl_ui/properties_scene.py
release/scripts/startup/bl_ui/space_clip.py
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_tracking.h
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/movieclip.c
source/blender/blenkernel/intern/tracking.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/UI_resources.h
source/blender/editors/interface/resources.c
source/blender/editors/object/object_constraint.c
source/blender/editors/space_clip/clip_intern.h
source/blender/editors/space_clip/space_clip.c
source/blender/editors/space_clip/tracking_ops.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_tracking_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_tracking.c
source/blender/makesrna/intern/rna_userdef.c
source/creator/CMakeLists.txt
source/creator/creator.c

index d8f5ba9e115fdeff771f6315aa98363e6b8a66fb..a8e69db6e92b815210d805b2ea48fa771039edfc 100644 (file)
@@ -315,6 +315,10 @@ def creator(env):
     if not env['WITH_BF_SDL']:
         defs.append('DISABLE_SDL')
 
+    if env['WITH_BF_LIBMV']:
+        incs.append('#/extern/libmv')
+        defs.append('WITH_LIBMV')
+
     if env['WITH_BF_PYTHON']:
         incs.append('#/source/blender/python')
         defs.append('WITH_PYTHON')
index 592a2d0067b6c7e62713991e06a30c787d520296..327b898058a8be5bf627dd8ee31cbcdb9e2569cd 100644 (file)
@@ -27,6 +27,8 @@
 # Otherwise we get warnings here that we cant fix in external projects
 remove_strict_flags()
 
+add_subdirectory(colamd)
+
 if(WITH_BULLET)
        add_subdirectory(bullet2)
 endif()
index 97d5c94dbe07a2f200062b09655a2ced1e4e0126..3c3e4c137d39612c2b889e6bb6574a93b23276c6 100644 (file)
@@ -3,6 +3,7 @@
 Import('env')
 
 SConscript(['glew/SConscript'])
+SConscript(['colamd/SConscript'])
 
 if env['WITH_BF_ELTOPO']:
     SConscript(['eltopo/SConscript'])
diff --git a/extern/colamd/CMakeLists.txt b/extern/colamd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fe7a044
--- /dev/null
@@ -0,0 +1,41 @@
+# $Id$
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+#                 Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       ./Include
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+       Source/colamd.c
+       Source/colamd_global.c
+
+       Include//colamd.h
+)
+
+blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/colamd/Doc/ChangeLog b/extern/colamd/Doc/ChangeLog
new file mode 100644 (file)
index 0000000..29308e9
--- /dev/null
@@ -0,0 +1,129 @@
+May 31, 2007: version 2.7.0
+
+    * ported to 64-bit MATLAB
+
+    * subdirectories added (Source/, Include/, Lib/, Doc/, MATLAB/, Demo/)
+
+Dec 12, 2006, version 2.5.2
+
+    * minor MATLAB cleanup.  MATLAB functions renamed colamd2 and symamd2,
+       so that they do not conflict with the built-in versions.  Note that
+       the MATLAB built-in functions colamd and symamd are identical to
+       the colamd and symamd functions here.
+
+Aug 31, 2006: Version 2.5.1
+
+    * minor change to colamd.m and symamd.m, to use etree instead
+       of sparsfun.
+
+Apr. 30, 2006: Version 2.5
+
+    * colamd_recommended modified, to do more careful integer overflow
+       checking.  It now returns size_t, not int.  colamd_l_recommended
+       also returns size_t.  A zero is returned if an error occurs.  A
+       postive return value denotes success.  In v2.4 and earlier,
+       -1 was returned on error (an int or long).
+
+    * long replaced with UF_long integer, which is long except on WIN64.
+
+Nov 15, 2005:
+
+    * minor editting of comments; version number (2.4) unchanged.
+
+Changes from Version 2.3 to 2.4 (Aug 30, 2005)
+
+    * Makefile now relies on ../UFconfig/UFconfig.mk
+
+    * changed the dense row/col detection.  The meaning of the knobs
+       has thus changed.
+
+    * added an option to turn off aggressive absorption.  It was
+       always on in versions 2.3 and earlier.
+
+    * added a #define'd version number
+
+    * added a function pointer (colamd_printf) for COLAMD's printing.
+
+    * added a -DNPRINT option, to turn off printing at compile-time.
+
+    * added a check for integer overflow in colamd_recommended
+
+    * minor changes to allow for more simpler 100% test coverage
+
+    * bug fix.  If symamd v2.3 fails to allocate its copy of the input
+       matrix, then it erroneously frees a calloc'd workspace twice.
+       This bug has no effect on the MATLAB symamd mexFunction, since
+       mxCalloc terminates the mexFunction if it fails to allocate
+       memory.  Similarly, UMFPACK is not affected because it does not
+       use symamd.  The bug has no effect on the colamd ordering
+       routine in v2.3.
+
+Changes from Version 2.2 to 2.3 (Sept. 8, 2003)
+
+    * removed the call to the MATLAB spparms ('spumoni') function.
+       This can take a lot of time if you are ordering many small
+       matrices.  Only affects the MATLAB interface (colamdmex.c,
+       symamdmex.c, colamdtestmex.c, and symamdtestmex.c).  The
+       usage of the optional 2nd argument to the colamd and symamd
+       mexFunctions was changed accordingly.
+
+Changes from Version 2.1 to 2.2 (Sept. 23, 2002)
+
+    * extensive testing routines added (colamd_test.m, colamdtestmex.c,
+       and symamdtestmex.c), and the Makefile modified accordingly.
+
+    * a few typos in the comments corrected 
+
+    * use of the MATLAB "flops" command removed from colamd_demo, and an
+       m-file routine luflops.m added.
+
+    * an explicit typecast from unsigned to int added, for COLAMD_C and
+       COLAMD_R in colamd.h.
+
+    * #include <stdio.h> added to colamd_example.c
+
+
+Changes from Version 2.0 to 2.1 (May 4, 2001)
+
+    * TRUE and FALSE are predefined on some systems, so they are defined
+           here only if not already defined.
+    
+    * web site changed
+
+    * UNIX Makefile modified, to handle the case if "." is not in your path.
+
+
+Changes from Version 1.0 to 2.0 (January 31, 2000)
+
+    No bugs were found in version 1.1.  These changes merely add new
+    functionality.
+
+    * added the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro.
+
+    * moved the output statistics, from A, to a separate output argument.
+           The arguments changed for the C-callable routines.
+
+    * added colamd_report and symamd_report.
+
+    * added a C-callable symamd routine.  Formerly, symamd was only
+           available as a mexFunction from MATLAB.
+
+    * added error-checking to symamd.  Formerly, it assumed its input
+           was error-free.
+
+    * added the optional stats and knobs arguments to the symamd mexFunction
+
+    * deleted colamd_help.  A help message is still available from
+           "help colamd" and "help symamd" in MATLAB.
+
+    * deleted colamdtree.m and symamdtree.m.  Now, colamd.m and symamd.m
+           also do the elimination tree post-ordering.  The Version 1.1
+           colamd and symamd mexFunctions, which do not do the post-
+           ordering, are now visible as colamdmex and symamdmex from
+           MATLAB.  Essentialy, the post-ordering is now the default
+           behavior of colamd.m and symamd.m, to match the behavior of
+           colmmd and symmmd.  The post-ordering is only available in the
+           MATLAB interface, not the C-callable interface.
+
+    * made a slight change to the dense row/column detection in symamd,
+           to match the stated specifications.
diff --git a/extern/colamd/Doc/lesser.txt b/extern/colamd/Doc/lesser.txt
new file mode 100644 (file)
index 0000000..8add30a
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/extern/colamd/Include/UFconfig.h b/extern/colamd/Include/UFconfig.h
new file mode 100644 (file)
index 0000000..7b5e79e
--- /dev/null
@@ -0,0 +1,118 @@
+/* ========================================================================== */
+/* === UFconfig.h =========================================================== */
+/* ========================================================================== */
+
+/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
+ * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
+ *
+ * UFconfig.h provides the definition of the long integer.  On most systems,
+ * a C program can be compiled in LP64 mode, in which long's and pointers are
+ * both 64-bits, and int's are 32-bits.  Windows 64, however, uses the LLP64
+ * model, in which int's and long's are 32-bits, and long long's and pointers
+ * are 64-bits.
+ *
+ * SuiteSparse packages that include long integer versions are
+ * intended for the LP64 mode.  However, as a workaround for Windows 64
+ * (and perhaps other systems), the long integer can be redefined.
+ *
+ * If _WIN64 is defined, then the __int64 type is used instead of long.
+ *
+ * The long integer can also be defined at compile time.  For example, this
+ * could be added to UFconfig.mk:
+ *
+ * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \
+ *   -D'UF_long_id="%lld"'
+ *
+ * This file defines UF_long as either long (on all but _WIN64) or
+ * __int64 on Windows 64.  The intent is that a UF_long is always a 64-bit
+ * integer in a 64-bit code.  ptrdiff_t might be a better choice than long;
+ * it is always the same size as a pointer.
+ *
+ * This file also defines the SUITESPARSE_VERSION and related definitions.
+ *
+ * Copyright (c) 2007, University of Florida.  No licensing restrictions
+ * apply to this file or to the UFconfig directory.  Author: Timothy A. Davis.
+ */
+
+#ifndef _UFCONFIG_H
+#define _UFCONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <limits.h>
+
+/* ========================================================================== */
+/* === UF_long ============================================================== */
+/* ========================================================================== */
+
+#ifndef UF_long
+
+#ifdef _WIN64
+
+#define UF_long __int64
+#define UF_long_max _I64_MAX
+#define UF_long_id "%I64d"
+
+#else
+
+#define UF_long long
+#define UF_long_max LONG_MAX
+#define UF_long_id "%ld"
+
+#endif
+#endif
+
+/* ========================================================================== */
+/* === SuiteSparse version ================================================== */
+/* ========================================================================== */
+
+/* SuiteSparse is not a package itself, but a collection of packages, some of
+ * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD,
+ * COLAMD, CAMD, and CCOLAMD, etc).  A version number is provided here for the
+ * collection itself.  The versions of packages within each version of
+ * SuiteSparse are meant to work together.  Combining one packge from one
+ * version of SuiteSparse, with another package from another version of
+ * SuiteSparse, may or may not work.
+ *
+ * SuiteSparse Version 3.4.0 contains the following packages:
+ *
+ *  AMD                    version 2.2.0
+ *  CAMD           version 2.2.0
+ *  COLAMD         version 2.7.1
+ *  CCOLAMD        version 2.7.1
+ *  CHOLMOD        version 1.7.1
+ *  CSparse        version 2.2.3
+ *  CXSparse       version 2.2.3
+ *  KLU                    version 1.1.0
+ *  BTF                    version 1.1.0
+ *  LDL                    version 2.0.1
+ *  UFconfig       version number is the same as SuiteSparse
+ *  UMFPACK        version 5.4.0
+ *  RBio           version 1.1.2
+ *  UFcollection    version 1.2.0
+ *  LINFACTOR       version 1.1.0
+ *  MESHND          version 1.1.1
+ *  SSMULT          version 2.0.0
+ *  MATLAB_Tools    no specific version number
+ *  SuiteSparseQR   version 1.1.2
+ *
+ * Other package dependencies:
+ *  BLAS           required by CHOLMOD and UMFPACK
+ *  LAPACK         required by CHOLMOD
+ *  METIS 4.0.1            required by CHOLMOD (optional) and KLU (optional)
+ */
+
+#define SUITESPARSE_DATE "May 20, 2009"
+#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define SUITESPARSE_MAIN_VERSION 3
+#define SUITESPARSE_SUB_VERSION 4
+#define SUITESPARSE_SUBSUB_VERSION 0
+#define SUITESPARSE_VERSION \
+    SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/extern/colamd/Include/colamd.h b/extern/colamd/Include/colamd.h
new file mode 100644 (file)
index 0000000..26372d8
--- /dev/null
@@ -0,0 +1,255 @@
+/* ========================================================================== */
+/* === colamd/symamd prototypes and definitions ============================= */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD include file
+
+    You must include this file (colamd.h) in any routine that uses colamd,
+    symamd, or the related macros and definitions.
+
+    Authors:
+
+       The authors of the code itself are Stefan I. Larimore and Timothy A.
+       Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+       developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+       Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+       This work was supported by the National Science Foundation, under
+       grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+       Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+
+       THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+       EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+       Permission is hereby granted to use, copy, modify, and/or distribute
+       this program, provided that the Copyright, this License, and the
+       Availability of the original version is retained on all copies and made
+       accessible to the end-user of any code or package that includes COLAMD
+       or any modified version of COLAMD. 
+
+    Availability:
+
+       The colamd/symamd library is available at
+
+           http://www.cise.ufl.edu/research/sparse/colamd/
+
+       This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h
+       file.  It is required by the colamd.c, colamdmex.c, and symamdmex.c
+       files, and by any C code that calls the routines whose prototypes are
+       listed below, or that uses the colamd/symamd definitions listed below.
+
+*/
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+/* make it easy for C++ programs to include COLAMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === COLAMD version ======================================================= */
+/* ========================================================================== */
+
+/* COLAMD Version 2.4 and later will include the following definitions.
+ * As an example, to test if the version you are using is 2.4 or later:
+ *
+ * #ifdef COLAMD_VERSION
+ *     if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *  #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4))
+ *    printf ("This is version 2.4 or later\n") ;
+ *  #else
+ *    printf ("This is an early version\n") ;
+ *  #endif
+ *
+ * Versions 2.3 and earlier of COLAMD do not include a #define'd version number.
+ */
+
+#define COLAMD_DATE "Nov 1, 2007"
+#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 7
+#define COLAMD_SUBSUB_VERSION 1
+#define COLAMD_VERSION \
+       COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION)
+
+/* ========================================================================== */
+/* === Knob and statistics definitions ====================================== */
+/* ========================================================================== */
+
+/* size of the knobs [ ] array.  Only knobs [0..1] are currently used. */
+#define COLAMD_KNOBS 20
+
+/* number of output statistics.  Only stats [0..6] are currently used. */
+#define COLAMD_STATS 20
+
+/* knobs [0] and stats [0]: dense row knob and output statistic. */
+#define COLAMD_DENSE_ROW 0
+
+/* knobs [1] and stats [1]: dense column knob and output statistic. */
+#define COLAMD_DENSE_COL 1
+
+/* knobs [2]: aggressive absorption */
+#define COLAMD_AGGRESSIVE 2
+
+/* stats [2]: memory defragmentation count output statistic */
+#define COLAMD_DEFRAG_COUNT 2
+
+/* stats [3]: colamd status:  zero OK, > 0 warning or notice, < 0 error */
+#define COLAMD_STATUS 3
+
+/* stats [4..6]: error info, or info on jumbled columns */ 
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+/* error codes returned in stats [3]: */
+#define COLAMD_OK                              (0)
+#define COLAMD_OK_BUT_JUMBLED                  (1)
+#define COLAMD_ERROR_A_not_present             (-1)
+#define COLAMD_ERROR_p_not_present             (-2)
+#define COLAMD_ERROR_nrow_negative             (-3)
+#define COLAMD_ERROR_ncol_negative             (-4)
+#define COLAMD_ERROR_nnz_negative              (-5)
+#define COLAMD_ERROR_p0_nonzero                        (-6)
+#define COLAMD_ERROR_A_too_small               (-7)
+#define COLAMD_ERROR_col_length_negative       (-8)
+#define COLAMD_ERROR_row_index_out_of_bounds   (-9)
+#define COLAMD_ERROR_out_of_memory             (-10)
+#define COLAMD_ERROR_internal_error            (-999)
+
+
+/* ========================================================================== */
+/* === Prototypes of user-callable routines ================================= */
+/* ========================================================================== */
+
+/* define UF_long */
+#include "UFconfig.h"
+
+size_t colamd_recommended      /* returns recommended value of Alen, */
+                               /* or 0 if input arguments are erroneous */
+(
+    int nnz,                   /* nonzeros in A */
+    int n_row,                 /* number of rows in A */
+    int n_col                  /* number of columns in A */
+) ;
+
+size_t colamd_l_recommended    /* returns recommended value of Alen, */
+                               /* or 0 if input arguments are erroneous */
+(
+    UF_long nnz,               /* nonzeros in A */
+    UF_long n_row,             /* number of rows in A */
+    UF_long n_col              /* number of columns in A */
+) ;
+
+void colamd_set_defaults       /* sets default parameters */
+(                              /* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]        /* parameter settings for colamd */
+) ;
+
+void colamd_l_set_defaults     /* sets default parameters */
+(                              /* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]        /* parameter settings for colamd */
+) ;
+
+int colamd                     /* returns (1) if successful, (0) otherwise*/
+(                              /* A and p arguments are modified on output */
+    int n_row,                 /* number of rows in A */
+    int n_col,                 /* number of columns in A */
+    int Alen,                  /* size of the array A */
+    int A [],                  /* row indices of A, of size Alen */
+    int p [],                  /* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    int stats [COLAMD_STATS]   /* colamd output statistics and error codes */
+) ;
+
+UF_long colamd_l               /* returns (1) if successful, (0) otherwise*/
+(                              /* A and p arguments are modified on output */
+    UF_long n_row,             /* number of rows in A */
+    UF_long n_col,             /* number of columns in A */
+    UF_long Alen,              /* size of the array A */
+    UF_long A [],              /* row indices of A, of size Alen */
+    UF_long p [],              /* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */
+) ;
+
+int symamd                             /* return (1) if OK, (0) otherwise */
+(
+    int n,                             /* number of rows and columns of A */
+    int A [],                          /* row indices of A */
+    int p [],                          /* column pointers of A */
+    int perm [],                       /* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],       /* parameters (uses defaults if NULL) */
+    int stats [COLAMD_STATS],          /* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+                                       /* pointer to calloc (ANSI C) or */
+                                       /* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+                                       /* pointer to free (ANSI C) or */
+                                       /* mxFree (for MATLAB mexFunction) */
+) ;
+
+UF_long symamd_l                       /* return (1) if OK, (0) otherwise */
+(
+    UF_long n,                         /* number of rows and columns of A */
+    UF_long A [],                      /* row indices of A */
+    UF_long p [],                      /* column pointers of A */
+    UF_long perm [],                   /* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],       /* parameters (uses defaults if NULL) */
+    UF_long stats [COLAMD_STATS],      /* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+                                       /* pointer to calloc (ANSI C) or */
+                                       /* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+                                       /* pointer to free (ANSI C) or */
+                                       /* mxFree (for MATLAB mexFunction) */
+) ;
+
+void colamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void colamd_l_report
+(
+    UF_long stats [COLAMD_STATS]
+) ;
+
+void symamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void symamd_l_report
+(
+    UF_long stats [COLAMD_STATS]
+) ;
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN int (*colamd_printf) (const char *, ...) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COLAMD_H */
diff --git a/extern/colamd/README.txt b/extern/colamd/README.txt
new file mode 100644 (file)
index 0000000..5ed81c7
--- /dev/null
@@ -0,0 +1,127 @@
+The COLAMD ordering method - Version 2.7
+-------------------------------------------------------------------------------
+
+The COLAMD column approximate minimum degree ordering algorithm computes
+a permutation vector P such that the LU factorization of A (:,P)
+tends to be sparser than that of A.  The Cholesky factorization of
+(A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A.
+SYMAMD is a symmetric minimum degree ordering method based on COLAMD,
+available as a MATLAB-callable function.  It constructs a matrix M such
+that M'*M has the same pattern as A, and then uses COLAMD to compute a column
+ordering of M.  Colamd and symamd tend to be faster and generate better
+orderings than their MATLAB counterparts, colmmd and symmmd.
+
+To compile and test the colamd m-files and mexFunctions, just unpack the
+COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from
+within that directory.  Next, type colamd_test to compile and test colamd
+and symamd.  This will work on any computer with MATLAB (Unix, PC, or Mac).
+Alternatively, type "make" (in Unix) to compile and run a simple example C
+code, without using MATLAB.
+
+To compile and install the colamd m-files and mexFunctions, just cd to
+COLAMD/MATLAB and type colamd_install in the MATLAB command window.
+A short demo will run.  Optionally, type colamd_test to run an extensive tests.
+Type "make" in Unix in the COLAMD directory to compile the C-callable
+library and to run a short demo.
+
+If you have MATLAB 7.2 or earlier, you must first edit UFconfig/UFconfig.h to
+remove the "-largeArrayDims" option from the MEX command (or just use
+colamd_make.m inside MATLAB).
+
+Colamd is a built-in routine in MATLAB, available from The 
+Mathworks, Inc.  Under most cases, the compiled COLAMD from Versions 2.0 to the
+current version do not differ.  Colamd Versions 2.2 and 2.3 differ only in their
+mexFunction interaces to MATLAB.  v2.4 fixes a bug in the symamd routine in
+v2.3.  The bug (in v2.3 and earlier) has no effect on the MATLAB symamd
+mexFunction.  v2.5 adds additional checks for integer overflow, so that
+the "int" version can be safely used with 64-bit pointers.  Refer to the
+ChangeLog for more details.
+
+To use colamd and symamd within an application written in C, all you need are
+colamd.c, colamd_global.c, and colamd.h, which are the C-callable
+colamd/symamd codes.  See colamd.c for more information on how to call
+colamd from a C program.
+
+Requires UFconfig, in the ../UFconfig directory relative to this directory.
+
+       Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+
+       See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
+       file) for the License.
+
+
+Related papers:
+
+       T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+       minimum degree ordering algorithm, ACM Transactions on Mathematical
+       Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+       T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+       an approximate column minimum degree ordering algorithm, ACM
+       Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+       2004.
+
+       "An approximate minimum degree column ordering algorithm",
+       S. I. Larimore, MS Thesis, Dept. of Computer and Information
+       Science and Engineering, University of Florida, Gainesville, FL,
+       1998.  CISE Tech Report TR-98-016.  Available at 
+       ftp://ftp.cise.ufl.edu/cis/tech-reports/tr98/tr98-016.ps
+       via anonymous ftp.
+
+       Approximate Deficiency for Ordering the Columns of a Matrix,
+       J. L. Kern, Senior Thesis, Dept. of Computer and Information
+       Science and Engineering, University of Florida, Gainesville, FL,
+       1999.  Available at http://www.cise.ufl.edu/~davis/Kern/kern.ps 
+
+
+Authors:  Stefan I. Larimore and Timothy A. Davis, University of Florida,
+in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara),
+and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work
+he did while at Oak Ridge National Laboratory). 
+
+COLAMD files:
+
+    Demo           simple demo
+    Doc                    additional documentation (see colamd.c for more)
+    Include        include file
+    Lib                    compiled C-callable library
+    Makefile       primary Unix Makefile
+    MATLAB         MATLAB functions
+    README.txt     this file
+    Source         C source code
+
+    ./Demo:
+    colamd_example.c       simple example
+    colamd_example.out     output of colamd_example.c
+    colamd_l_example.c     simple example, long integers
+    colamd_l_example.out    output of colamd_l_example.c
+    Makefile               Makefile for C demos
+
+    ./Doc:
+    ChangeLog      change log
+    lesser.txt     license
+
+    ./Include:
+    colamd.h       include file
+
+    ./Lib:
+    Makefile       Makefile for C-callable library
+
+    ./MATLAB:
+    colamd2.m          MATLAB interface for colamd2
+    colamd_demo.m      simple demo
+    colamd_install.m   compile and install colamd2 and symamd2
+    colamd_make.m      compile colamd2 and symamd2
+    colamdmex.ca       MATLAB mexFunction for colamd2
+    colamd_test.m      extensive test
+    colamdtestmex.c    test function for colamd
+    Contents.m         contents of the MATLAB directory
+    luflops.m          test code
+    Makefile           Makefile for MATLAB functions
+    symamd2.m          MATLAB interface for symamd2
+    symamdmex.c                MATLAB mexFunction for symamd2
+    symamdtestmex.c    test function for symamd
+
+    ./Source:
+    colamd.c           primary source code
+    colamd_global.c    globally defined function pointers (malloc, free, ...)
diff --git a/extern/colamd/SConscript b/extern/colamd/SConscript
new file mode 100644 (file)
index 0000000..7930e3a
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+import sys
+import os
+
+Import('env')
+
+defs = ''
+cflags = []
+
+src = env.Glob('Source/*.c')
+
+incs = './Include'
+
+env.BlenderLib ( libname = 'extern_colamd', sources=src, includes=Split(incs), defines=Split(defs), libtype=['extern', 'player'], priority=[20,137], compileflags=cflags )
diff --git a/extern/colamd/Source/colamd.c b/extern/colamd/Source/colamd.c
new file mode 100644 (file)
index 0000000..5fe20d6
--- /dev/null
@@ -0,0 +1,3611 @@
+/* ========================================================================== */
+/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD
+
+    colamd:  an approximate minimum degree column ordering algorithm,
+       for LU factorization of symmetric or unsymmetric matrices,
+       QR factorization, least squares, interior point methods for
+       linear programming problems, and other related problems.
+
+    symamd:  an approximate minimum degree ordering algorithm for Cholesky
+       factorization of symmetric matrices.
+
+    Purpose:
+
+       Colamd computes a permutation Q such that the Cholesky factorization of
+       (AQ)'(AQ) has less fill-in and requires fewer floating point operations
+       than A'A.  This also provides a good ordering for sparse partial
+       pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+       factorization, and P is computed during numerical factorization via
+       conventional partial pivoting with row interchanges.  Colamd is the
+       column ordering method used in SuperLU, part of the ScaLAPACK library.
+       It is also available as built-in function in MATLAB Version 6,
+       available from MathWorks, Inc. (http://www.mathworks.com).  This
+       routine can be used in place of colmmd in MATLAB.
+
+       Symamd computes a permutation P of a symmetric matrix A such that the
+       Cholesky factorization of PAP' has less fill-in and requires fewer
+       floating point operations than A.  Symamd constructs a matrix M such
+       that M'M has the same nonzero pattern of A, and then orders the columns
+       of M using colmmd.  The column ordering of M is then returned as the
+       row and column ordering P of A. 
+
+    Authors:
+
+       The authors of the code itself are Stefan I. Larimore and Timothy A.
+       Davis (davis at cise.ufl.edu), University of Florida.  The algorithm was
+       developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+       Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+       This work was supported by the National Science Foundation, under
+       grants DMS-9504974 and DMS-9803599.
+
+    Copyright and License:
+
+       Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+       COLAMD is also available under alternate licenses, contact T. Davis
+       for details.
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+
+       You should have received a copy of the GNU Lesser General Public
+       License along with this library; if not, write to the Free Software
+       Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+       USA
+
+       Permission is hereby granted to use or copy this program under the
+       terms of the GNU LGPL, provided that the Copyright, this License,
+       and the Availability of the original version is retained on all copies.
+       User documentation of any code that uses this code or any modified
+       version of this code must cite the Copyright, this License, the
+       Availability note, and "Used by permission." Permission to modify
+       the code and to distribute modified code is granted, provided the
+       Copyright, this License, and the Availability note are retained,
+       and a notice that the code was modified is included.
+
+    Availability:
+
+       The colamd/symamd library is available at
+
+           http://www.cise.ufl.edu/research/sparse/colamd/
+
+       This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
+       file.  It requires the colamd.h file.  It is required by the colamdmex.c
+       and symamdmex.c files, for the MATLAB interface to colamd and symamd.
+       Appears as ACM Algorithm 836.
+
+    See the ChangeLog file for changes since Version 1.0.
+
+    References:
+
+       T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+       minimum degree ordering algorithm, ACM Transactions on Mathematical
+       Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+       T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+       an approximate column minimum degree ordering algorithm, ACM
+       Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+       2004.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/* COLAMD includes both int and UF_long versions of all its routines.  The
+ * description below is for the int version.  For UF_long, all int arguments
+ * become UF_long.  UF_long is normally defined as long, except for WIN64.
+
+    ----------------------------------------------------------------------------
+    colamd_recommended:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           size_t colamd_recommended (int nnz, int n_row, int n_col) ;
+           size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
+               UF_long n_col) ;
+
+       Purpose:
+
+           Returns recommended value of Alen for use by colamd.  Returns 0
+           if any input argument is negative.  The use of this routine
+           is optional.  Not needed for symamd, which dynamically allocates
+           its own memory.
+
+           Note that in v2.4 and earlier, these routines returned int or long.
+           They now return a value of type size_t.
+
+       Arguments (all input arguments):
+
+           int nnz ;           Number of nonzeros in the matrix A.  This must
+                               be the same value as p [n_col] in the call to
+                               colamd - otherwise you will get a wrong value
+                               of the recommended memory to use.
+
+           int n_row ;         Number of rows in the matrix A.
+
+           int n_col ;         Number of columns in the matrix A.
+
+    ----------------------------------------------------------------------------
+    colamd_set_defaults:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+           colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+       Purpose:
+
+           Sets the default parameters.  The use of this routine is optional.
+
+       Arguments:
+
+           double knobs [COLAMD_KNOBS] ;       Output only.
+
+               NOTE: the meaning of the dense row/col knobs has changed in v2.4
+
+               knobs [0] and knobs [1] control dense row and col detection:
+
+               Colamd: rows with more than
+               max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
+               entries are removed prior to ordering.  Columns with more than
+               max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
+               entries are removed prior to
+               ordering, and placed last in the output column ordering. 
+
+               Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
+               Rows and columns with more than
+               max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
+               entries are removed prior to ordering, and placed last in the
+               output ordering.
+
+               COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+               respectively, in colamd.h.  Default values of these two knobs
+               are both 10.  Currently, only knobs [0] and knobs [1] are
+               used, but future versions may use more knobs.  If so, they will
+               be properly set to their defaults by the future version of
+               colamd_set_defaults, so that the code that calls colamd will
+               not need to change, assuming that you either use
+               colamd_set_defaults, or pass a (double *) NULL pointer as the
+               knobs array to colamd or symamd.
+
+           knobs [2]: aggressive absorption
+
+               knobs [COLAMD_AGGRESSIVE] controls whether or not to do
+               aggressive absorption during the ordering.  Default is TRUE.
+
+
+    ----------------------------------------------------------------------------
+    colamd:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           int colamd (int n_row, int n_col, int Alen, int *A, int *p,
+               double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
+           UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
+               UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
+               UF_long stats [COLAMD_STATS]) ;
+
+       Purpose:
+
+           Computes a column ordering (Q) of A such that P(AQ)=LU or
+           (AQ)'AQ=LL' have less fill-in and require fewer floating point
+           operations than factorizing the unpermuted matrix A or A'A,
+           respectively.
+           
+       Returns:
+
+           TRUE (1) if successful, FALSE (0) otherwise.
+
+       Arguments:
+
+           int n_row ;         Input argument.
+
+               Number of rows in the matrix A.
+               Restriction:  n_row >= 0.
+               Colamd returns FALSE if n_row is negative.
+
+           int n_col ;         Input argument.
+
+               Number of columns in the matrix A.
+               Restriction:  n_col >= 0.
+               Colamd returns FALSE if n_col is negative.
+
+           int Alen ;          Input argument.
+
+               Restriction (see note):
+               Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
+               Colamd returns FALSE if these conditions are not met.
+
+               Note:  this restriction makes an modest assumption regarding
+               the size of the two typedef's structures in colamd.h.
+               We do, however, guarantee that
+
+                       Alen >= colamd_recommended (nnz, n_row, n_col)
+
+               will be sufficient.  Note: the macro version does not check
+               for integer overflow, and thus is not recommended.  Use
+               the colamd_recommended routine instead.
+
+           int A [Alen] ;      Input argument, undefined on output.
+
+               A is an integer array of size Alen.  Alen must be at least as
+               large as the bare minimum value given above, but this is very
+               low, and can result in excessive run time.  For best
+               performance, we recommend that Alen be greater than or equal to
+               colamd_recommended (nnz, n_row, n_col), which adds
+               nnz/5 to the bare minimum value given above.
+
+               On input, the row indices of the entries in column c of the
+               matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
+               in a given column c need not be in ascending order, and
+               duplicate row indices may be be present.  However, colamd will
+               work a little faster if both of these conditions are met
+               (Colamd puts the matrix into this format, if it finds that the
+               the conditions are not met).
+
+               The matrix is 0-based.  That is, rows are in the range 0 to
+               n_row-1, and columns are in the range 0 to n_col-1.  Colamd
+               returns FALSE if any row index is out of range.
+
+               The contents of A are modified during ordering, and are
+               undefined on output.
+
+           int p [n_col+1] ;   Both input and output argument.
+
+               p is an integer array of size n_col+1.  On input, it holds the
+               "pointers" for the column form of the matrix A.  Column c of
+               the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+               entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+               for all c in the range 0 to n_col-1.  The value p [n_col] is
+               thus the total number of entries in the pattern of the matrix A.
+               Colamd returns FALSE if these conditions are not met.
+
+               On output, if colamd returns TRUE, the array p holds the column
+               permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+               the first column index in the new ordering, and p [n_col-1] is
+               the last.  That is, p [k] = j means that column j of A is the
+               kth pivot column, in AQ, where k is in the range 0 to n_col-1
+               (p [0] = j means that column j of A is the first column in AQ).
+
+               If colamd returns FALSE, then no permutation is returned, and
+               p is undefined on output.
+
+           double knobs [COLAMD_KNOBS] ;       Input argument.
+
+               See colamd_set_defaults for a description.
+
+           int stats [COLAMD_STATS] ;          Output argument.
+
+               Statistics on the ordering, and error status.
+               See colamd.h for related definitions.
+               Colamd returns FALSE if stats is not present.
+
+               stats [0]:  number of dense or empty rows ignored.
+
+               stats [1]:  number of dense or empty columns ignored (and
+                               ordered last in the output permutation p)
+                               Note that a row can become "empty" if it
+                               contains only "dense" and/or "empty" columns,
+                               and similarly a column can become "empty" if it
+                               only contains "dense" and/or "empty" rows.
+
+               stats [2]:  number of garbage collections performed.
+                               This can be excessively high if Alen is close
+                               to the minimum required value.
+
+               stats [3]:  status code.  < 0 is an error code.
+                           > 1 is a warning or notice.
+
+                       0       OK.  Each column of the input matrix contained
+                               row indices in increasing order, with no
+                               duplicates.
+
+                       1       OK, but columns of input matrix were jumbled
+                               (unsorted columns or duplicate entries).  Colamd
+                               had to do some extra work to sort the matrix
+                               first and remove duplicate entries, but it
+                               still was able to return a valid permutation
+                               (return value of colamd was TRUE).
+
+                                       stats [4]: highest numbered column that
+                                               is unsorted or has duplicate
+                                               entries.
+                                       stats [5]: last seen duplicate or
+                                               unsorted row index.
+                                       stats [6]: number of duplicate or
+                                               unsorted row indices.
+
+                       -1      A is a null pointer
+
+                       -2      p is a null pointer
+
+                       -3      n_row is negative
+
+                                       stats [4]: n_row
+
+                       -4      n_col is negative
+
+                                       stats [4]: n_col
+
+                       -5      number of nonzeros in matrix is negative
+
+                                       stats [4]: number of nonzeros, p [n_col]
+
+                       -6      p [0] is nonzero
+
+                                       stats [4]: p [0]
+
+                       -7      A is too small
+
+                                       stats [4]: required size
+                                       stats [5]: actual size (Alen)
+
+                       -8      a column has a negative number of entries
+
+                                       stats [4]: column with < 0 entries
+                                       stats [5]: number of entries in col
+
+                       -9      a row index is out of bounds
+
+                                       stats [4]: column with bad row index
+                                       stats [5]: bad row index
+                                       stats [6]: n_row, # of rows of matrx
+
+                       -10     (unused; see symamd.c)
+
+                       -999    (unused; see symamd.c)
+
+               Future versions may return more statistics in the stats array.
+
+       Example:
+       
+           See http://www.cise.ufl.edu/research/sparse/colamd/example.c
+           for a complete example.
+
+           To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+           the following nonzero pattern
+
+               x 0 x 0
+               x 0 x x
+               0 x x 0
+               0 0 x x
+               x x 0 0
+
+           with default knobs and no output statistics, do the following:
+
+               #include "colamd.h"
+               #define ALEN 100
+               int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
+               int p [ ] = {0, 3, 5, 9, 11} ;
+               int stats [COLAMD_STATS] ;
+               colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+           The permutation is returned in the array p, and A is destroyed.
+
+    ----------------------------------------------------------------------------
+    symamd:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           int symamd (int n, int *A, int *p, int *perm,
+               double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
+               void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+           UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
+               double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
+               void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+
+       Purpose:
+
+           The symamd routine computes an ordering P of a symmetric sparse
+           matrix A such that the Cholesky factorization PAP' = LL' remains
+           sparse.  It is based on a column ordering of a matrix M constructed
+           so that the nonzero pattern of M'M is the same as A.  The matrix A
+           is assumed to be symmetric; only the strictly lower triangular part
+           is accessed.  You must pass your selected memory allocator (usually
+           calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
+           memory for the temporary matrix M.
+
+       Returns:
+
+           TRUE (1) if successful, FALSE (0) otherwise.
+
+       Arguments:
+
+           int n ;             Input argument.
+
+               Number of rows and columns in the symmetrix matrix A.
+               Restriction:  n >= 0.
+               Symamd returns FALSE if n is negative.
+
+           int A [nnz] ;       Input argument.
+
+               A is an integer array of size nnz, where nnz = p [n].
+               
+               The row indices of the entries in column c of the matrix are
+               held in A [(p [c]) ... (p [c+1]-1)].  The row indices in a
+               given column c need not be in ascending order, and duplicate
+               row indices may be present.  However, symamd will run faster
+               if the columns are in sorted order with no duplicate entries. 
+
+               The matrix is 0-based.  That is, rows are in the range 0 to
+               n-1, and columns are in the range 0 to n-1.  Symamd
+               returns FALSE if any row index is out of range.
+
+               The contents of A are not modified.
+
+           int p [n+1] ;       Input argument.
+
+               p is an integer array of size n+1.  On input, it holds the
+               "pointers" for the column form of the matrix A.  Column c of
+               the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+               entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+               for all c in the range 0 to n-1.  The value p [n] is
+               thus the total number of entries in the pattern of the matrix A.
+               Symamd returns FALSE if these conditions are not met.
+
+               The contents of p are not modified.
+
+           int perm [n+1] ;    Output argument.
+
+               On output, if symamd returns TRUE, the array perm holds the
+               permutation P, where perm [0] is the first index in the new
+               ordering, and perm [n-1] is the last.  That is, perm [k] = j
+               means that row and column j of A is the kth column in PAP',
+               where k is in the range 0 to n-1 (perm [0] = j means
+               that row and column j of A are the first row and column in
+               PAP').  The array is used as a workspace during the ordering,
+               which is why it must be of length n+1, not just n.
+
+           double knobs [COLAMD_KNOBS] ;       Input argument.
+
+               See colamd_set_defaults for a description.
+
+           int stats [COLAMD_STATS] ;          Output argument.
+
+               Statistics on the ordering, and error status.
+               See colamd.h for related definitions.
+               Symamd returns FALSE if stats is not present.
+
+               stats [0]:  number of dense or empty row and columns ignored
+                               (and ordered last in the output permutation 
+                               perm).  Note that a row/column can become
+                               "empty" if it contains only "dense" and/or
+                               "empty" columns/rows.
+
+               stats [1]:  (same as stats [0])
+
+               stats [2]:  number of garbage collections performed.
+
+               stats [3]:  status code.  < 0 is an error code.
+                           > 1 is a warning or notice.
+
+                       0       OK.  Each column of the input matrix contained
+                               row indices in increasing order, with no
+                               duplicates.
+
+                       1       OK, but columns of input matrix were jumbled
+                               (unsorted columns or duplicate entries).  Symamd
+                               had to do some extra work to sort the matrix
+                               first and remove duplicate entries, but it
+                               still was able to return a valid permutation
+                               (return value of symamd was TRUE).
+
+                                       stats [4]: highest numbered column that
+                                               is unsorted or has duplicate
+                                               entries.
+                                       stats [5]: last seen duplicate or
+                                               unsorted row index.
+                                       stats [6]: number of duplicate or
+                                               unsorted row indices.
+
+                       -1      A is a null pointer
+
+                       -2      p is a null pointer
+
+                       -3      (unused, see colamd.c)
+
+                       -4      n is negative
+
+                                       stats [4]: n
+
+                       -5      number of nonzeros in matrix is negative
+
+                                       stats [4]: # of nonzeros (p [n]).
+
+                       -6      p [0] is nonzero
+
+                                       stats [4]: p [0]
+
+                       -7      (unused)
+
+                       -8      a column has a negative number of entries
+
+                                       stats [4]: column with < 0 entries
+                                       stats [5]: number of entries in col
+
+                       -9      a row index is out of bounds
+
+                                       stats [4]: column with bad row index
+                                       stats [5]: bad row index
+                                       stats [6]: n_row, # of rows of matrx
+
+                       -10     out of memory (unable to allocate temporary
+                               workspace for M or count arrays using the
+                               "allocate" routine passed into symamd).
+
+               Future versions may return more statistics in the stats array.
+
+           void * (*allocate) (size_t, size_t)
+
+               A pointer to a function providing memory allocation.  The
+               allocated memory must be returned initialized to zero.  For a
+               C application, this argument should normally be a pointer to
+               calloc.  For a MATLAB mexFunction, the routine mxCalloc is
+               passed instead.
+
+           void (*release) (size_t, size_t)
+
+               A pointer to a function that frees memory allocated by the
+               memory allocation routine above.  For a C application, this
+               argument should normally be a pointer to free.  For a MATLAB
+               mexFunction, the routine mxFree is passed instead.
+
+
+    ----------------------------------------------------------------------------
+    colamd_report:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           colamd_report (int stats [COLAMD_STATS]) ;
+           colamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+       Purpose:
+
+           Prints the error status and statistics recorded in the stats
+           array on the standard error output (for a standard C routine)
+           or on the MATLAB output (for a mexFunction).
+
+       Arguments:
+
+           int stats [COLAMD_STATS] ;  Input only.  Statistics from colamd.
+
+
+    ----------------------------------------------------------------------------
+    symamd_report:
+    ----------------------------------------------------------------------------
+
+       C syntax:
+
+           #include "colamd.h"
+           symamd_report (int stats [COLAMD_STATS]) ;
+           symamd_l_report (UF_long stats [COLAMD_STATS]) ;
+
+       Purpose:
+
+           Prints the error status and statistics recorded in the stats
+           array on the standard error output (for a standard C routine)
+           or on the MATLAB output (for a mexFunction).
+
+       Arguments:
+
+           int stats [COLAMD_STATS] ;  Input only.  Statistics from symamd.
+
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions  ======================================== */
+/* ========================================================================== */
+
+/* Ensure that debugging is turned off: */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* turn on debugging by uncommenting the following line
+ #undef NDEBUG
+*/
+
+/*
+   Our "scaffolding code" philosophy:  In our opinion, well-written library
+   code should keep its "debugging" code, and just normally have it turned off
+   by the compiler so as not to interfere with performance.  This serves
+   several purposes:
+
+   (1) assertions act as comments to the reader, telling you what the code
+       expects at that point.  All assertions will always be true (unless
+       there really is a bug, of course).
+
+   (2) leaving in the scaffolding code assists anyone who would like to modify
+       the code, or understand the algorithm (by reading the debugging output,
+       one can get a glimpse into what the code is doing).
+
+   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
+       and "should" be fully functional and bug-free ... but you never know...
+
+    The code will become outrageously slow when debugging is
+    enabled.  To control the level of debugging output, set an environment
+    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
+    you should see the following message on the standard output:
+
+       colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+    or a similar message for symamd.  If you don't, then debugging has not
+    been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include <limits.h>
+#include <math.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif /* MATLAB_MEX_FILE */
+
+#if !defined (NPRINT) || !defined (NDEBUG)
+#include <stdio.h>
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* ========================================================================== */
+/* === int or UF_long ======================================================= */
+/* ========================================================================== */
+
+/* define UF_long */
+#include "UFconfig.h"
+
+#ifdef DLONG
+
+#define Int UF_long
+#define ID  UF_long_id
+#define Int_MAX UF_long_max
+
+#define COLAMD_recommended colamd_l_recommended
+#define COLAMD_set_defaults colamd_l_set_defaults
+#define COLAMD_MAIN colamd_l
+#define SYMAMD_MAIN symamd_l
+#define COLAMD_report colamd_l_report
+#define SYMAMD_report symamd_l_report
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define COLAMD_recommended colamd_recommended
+#define COLAMD_set_defaults colamd_set_defaults
+#define COLAMD_MAIN colamd
+#define SYMAMD_MAIN symamd
+#define COLAMD_report colamd_report
+#define SYMAMD_report symamd_report
+
+#endif
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures.  They are used only for colamd_recommended. */
+
+typedef struct Colamd_Col_struct
+{
+    Int start ;                /* index for A of first row in this column, or DEAD */
+                       /* if column is dead */
+    Int length ;       /* number of rows in this column */
+    union
+    {
+       Int thickness ; /* number of original columns represented by this */
+                       /* col, if the column is alive */
+       Int parent ;    /* parent in parent tree super-column structure, if */
+                       /* the column is dead */
+    } shared1 ;
+    union
+    {
+       Int score ;     /* the score used to maintain heap, if col is alive */
+       Int order ;     /* pivot ordering of this column, if col is dead */
+    } shared2 ;
+    union
+    {
+       Int headhash ;  /* head of a hash bucket, if col is at the head of */
+                       /* a degree list */
+       Int hash ;      /* hash value, if col is not in a degree list */
+       Int prev ;      /* previous column in degree list, if col is in a */
+                       /* degree list (but not at the head of a degree list) */
+    } shared3 ;
+    union
+    {
+       Int degree_next ;       /* next column, if col is in a degree list */
+       Int hash_next ;         /* next column, if col is in a hash list */
+    } shared4 ;
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+    Int start ;                /* index for A of first col in this row */
+    Int length ;       /* number of principal columns in this row */
+    union
+    {
+       Int degree ;    /* number of principal & non-principal columns in row */
+       Int p ;         /* used as a row pointer in init_rows_cols () */
+    } shared1 ;
+    union
+    {
+       Int mark ;      /* for computing set differences and marking dead rows*/
+       Int first_column ;/* first column in row (used in garbage collection) */
+    } shared2 ;
+
+} Colamd_Row ;
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
+#define PUBLIC
+#define PRIVATE static
+
+#define DENSE_DEGREE(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* Change for version 2.1:  define TRUE and FALSE only if not yet defined */  
+/* -------------------------------------------------------------------------- */
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#define EMPTY  (-1)
+
+/* Row and column status */
+#define ALIVE  (0)
+#define DEAD   (-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL         (-1)
+#define DEAD_NON_PRINCIPAL     (-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r)                 ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark)   (row_mark < ALIVE)
+#define ROW_IS_ALIVE(r)                        (Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c)                 (Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c)                        (Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c)       (Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r)                    { Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c)          { Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c)      { Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ========================================================================== */
+/* === Colamd reporting mechanism =========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
+#define INDEX(i) ((i)+1)
+#else
+/* In C, matrices are 0-based and indices are reported as such in *_report */
+#define INDEX(i) (i)
+#endif
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int p [],
+    Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    double knobs [COLAMD_KNOBS],
+    Int *p_n_row2,
+    Int *p_n_col2,
+    Int *p_max_deg
+) ;
+
+PRIVATE Int find_ordering
+(
+    Int n_row,
+    Int n_col,
+    Int Alen,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int n_col2,
+    Int max_deg,
+    Int pfree,
+    Int aggressive
+) ;
+
+PRIVATE void order_children
+(
+    Int n_col,
+    Colamd_Col Col [],
+    Int p []
+) ;
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+    Int n_col,
+    Colamd_Row Row [],
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int row_start,
+    Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+    Int tag_mark,
+    Int max_mark,
+    Int n_row,
+    Colamd_Row Row []
+) ;
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+) ;
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#include <assert.h>
+
+/* colamd_debug is the *ONLY* global variable, and is only */
+/* present when debugging */
+
+PRIVATE Int colamd_debug = 0 ; /* debug print level */
+
+#define DEBUG0(params) { PRINTF (params) ; }
+#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
+#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
+#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
+#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
+
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+
+PRIVATE void colamd_get_debug  /* gets the debug print level from getenv */
+(
+    char *method
+) ;
+
+PRIVATE void debug_deg_lists
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+) ;
+
+#else /* NDEBUG */
+
+/* === No debugging ========================================================= */
+
+#define DEBUG0(params) ;
+#define DEBUG1(params) ;
+#define DEBUG2(params) ;
+#define DEBUG3(params) ;
+#define DEBUG4(params) ;
+
+#define ASSERT(expression)
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === colamd_recommended =================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_recommended routine returns the suggested size for Alen.  This
+    value has been determined to provide good balance between the number of
+    garbage collections and the memory requirements for colamd.  If any
+    argument is negative, or if integer overflow occurs, a 0 is returned as an
+    error condition.  2*nnz space is required for the row and column
+    indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+    required for the Col and Row arrays, respectively, which are internal to
+    colamd (roughly 6*n_col + 4*n_row).  An additional n_col space is the
+    minimal amount of "elbow room", and nnz/5 more space is recommended for
+    run time efficiency.
+
+    Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
+
+    This function is not needed when using symamd.
+*/
+
+/* add two values of type size_t, and check for integer overflow */
+static size_t t_add (size_t a, size_t b, int *ok)
+{
+    (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
+    return ((*ok) ? (a + b) : 0) ;
+}
+
+/* compute a*k where k is a small integer, and check for integer overflow */
+static size_t t_mult (size_t a, size_t k, int *ok)
+{
+    size_t i, s = 0 ;
+    for (i = 0 ; i < k ; i++)
+    {
+       s = t_add (s, a, ok) ;
+    }
+    return (s) ;
+}
+
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col,ok) \
+    ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
+
+#define COLAMD_R(n_row,ok) \
+    ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
+
+
+PUBLIC size_t COLAMD_recommended       /* returns recommended value of Alen. */
+(
+    /* === Parameters ======================================================= */
+
+    Int nnz,                   /* number of nonzeros in A */
+    Int n_row,                 /* number of rows in A */
+    Int n_col                  /* number of columns in A */
+)
+{
+    size_t s, c, r ;
+    int ok = TRUE ;
+    if (nnz < 0 || n_row < 0 || n_col < 0)
+    {
+       return (0) ;
+    }
+    s = t_mult (nnz, 2, &ok) ;     /* 2*nnz */
+    c = COLAMD_C (n_col, &ok) ;            /* size of column structures */
+    r = COLAMD_R (n_row, &ok) ;            /* size of row structures */
+    s = t_add (s, c, &ok) ;
+    s = t_add (s, r, &ok) ;
+    s = t_add (s, n_col, &ok) ;            /* elbow room */
+    s = t_add (s, nnz/5, &ok) ;            /* elbow room */
+    ok = ok && (s < Int_MAX) ;
+    return (ok ? s : 0) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_set_defaults routine sets the default values of the user-
+    controllable parameters for colamd and symamd:
+
+       Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
+       entries are removed prior to ordering.  Columns with more than
+       max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
+       prior to ordering, and placed last in the output column ordering. 
+
+       Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
+       entries are removed prior to ordering, and placed last in the
+       output ordering.
+
+       knobs [0]       dense row control
+
+       knobs [1]       dense column control
+
+       knobs [2]       if nonzero, do aggresive absorption
+
+       knobs [3..19]   unused, but future versions might use this
+
+*/
+
+PUBLIC void COLAMD_set_defaults
+(
+    /* === Parameters ======================================================= */
+
+    double knobs [COLAMD_KNOBS]                /* knob array */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+
+    if (!knobs)
+    {
+       return ;                        /* no knobs to initialize */
+    }
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+       knobs [i] = 0 ;
+    }
+    knobs [COLAMD_DENSE_ROW] = 10 ;
+    knobs [COLAMD_DENSE_COL] = 10 ;
+    knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
+}
+
+
+/* ========================================================================== */
+/* === symamd =============================================================== */
+/* ========================================================================== */
+
+PUBLIC Int SYMAMD_MAIN                 /* return TRUE if OK, FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n,                             /* number of rows and columns of A */
+    Int A [],                          /* row indices of A */
+    Int p [],                          /* column pointers of A */
+    Int perm [],                       /* output permutation, size n+1 */
+    double knobs [COLAMD_KNOBS],       /* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS],          /* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+                                       /* pointer to calloc (ANSI C) or */
+                                       /* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+                                       /* pointer to free (ANSI C) or */
+                                       /* mxFree (for MATLAB mexFunction) */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *count ;               /* length of each column of M, and col pointer*/
+    Int *mark ;                        /* mark array for finding duplicate entries */
+    Int *M ;                   /* row indices of matrix M */
+    size_t Mlen ;              /* length of M */
+    Int n_row ;                        /* number of rows in M */
+    Int nnz ;                  /* number of entries in A */
+    Int i ;                    /* row index of A */
+    Int j ;                    /* column index of A */
+    Int k ;                    /* row index of M */ 
+    Int mnz ;                  /* number of nonzeros in M */
+    Int pp ;                   /* index into a column of A */
+    Int last_row ;             /* last row seen in the current column */
+    Int length ;               /* number of nonzeros in a column */
+
+    double cknobs [COLAMD_KNOBS] ;             /* knobs for colamd */
+    double default_knobs [COLAMD_KNOBS] ;      /* default knobs for colamd */
+
+#ifndef NDEBUG
+    colamd_get_debug ("symamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+       DEBUG0 (("symamd: stats not present\n")) ;
+       return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+       stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+       DEBUG0 (("symamd: A not present\n")) ;
+       return (FALSE) ;
+    }
+
+    if (!p)            /* p is not present */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+       DEBUG0 (("symamd: p not present\n")) ;
+       return (FALSE) ;
+    }
+
+    if (n < 0)         /* n must be >= 0 */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+       stats [COLAMD_INFO1] = n ;
+       DEBUG0 (("symamd: n negative %d\n", n)) ;
+       return (FALSE) ;
+    }
+
+    nnz = p [n] ;
+    if (nnz < 0)       /* nnz must be >= 0 */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+       stats [COLAMD_INFO1] = nnz ;
+       DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
+       return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+       stats [COLAMD_INFO1] = p [0] ;
+       DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
+       return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+       COLAMD_set_defaults (default_knobs) ;
+       knobs = default_knobs ;
+    }
+
+    /* === Allocate count and mark ========================================== */
+
+    count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!count)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+       DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
+       return (FALSE) ;
+    }
+
+    mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!mark)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+       (*release) ((void *) count) ;
+       DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
+       return (FALSE) ;
+    }
+
+    /* === Compute column counts of M, check if A is valid ================== */
+
+    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
+
+    for (i = 0 ; i < n ; i++)
+    {
+       mark [i] = -1 ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+       last_row = -1 ;
+
+       length = p [j+1] - p [j] ;
+       if (length < 0)
+       {
+           /* column pointers must be non-decreasing */
+           stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+           stats [COLAMD_INFO1] = j ;
+           stats [COLAMD_INFO2] = length ;
+           (*release) ((void *) count) ;
+           (*release) ((void *) mark) ;
+           DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
+           return (FALSE) ;
+       }
+
+       for (pp = p [j] ; pp < p [j+1] ; pp++)
+       {
+           i = A [pp] ;
+           if (i < 0 || i >= n)
+           {
+               /* row index i, in column j, is out of bounds */
+               stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+               stats [COLAMD_INFO1] = j ;
+               stats [COLAMD_INFO2] = i ;
+               stats [COLAMD_INFO3] = n ;
+               (*release) ((void *) count) ;
+               (*release) ((void *) mark) ;
+               DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
+               return (FALSE) ;
+           }
+
+           if (i <= last_row || mark [i] == j)
+           {
+               /* row index is unsorted or repeated (or both), thus col */
+               /* is jumbled.  This is a notice, not an error condition. */
+               stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+               stats [COLAMD_INFO1] = j ;
+               stats [COLAMD_INFO2] = i ;
+               (stats [COLAMD_INFO3]) ++ ;
+               DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
+           }
+
+           if (i > j && mark [i] != j)
+           {
+               /* row k of M will contain column indices i and j */
+               count [i]++ ;
+               count [j]++ ;
+           }
+
+           /* mark the row as having been seen in this column */
+           mark [i] = j ;
+
+           last_row = i ;
+       }
+    }
+
+    /* v2.4: removed free(mark) */
+
+    /* === Compute column pointers of M ===================================== */
+
+    /* use output permutation, perm, for column pointers of M */
+    perm [0] = 0 ;
+    for (j = 1 ; j <= n ; j++)
+    {
+       perm [j] = perm [j-1] + count [j-1] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+       count [j] = perm [j] ;
+    }
+
+    /* === Construct M ====================================================== */
+
+    mnz = perm [n] ;
+    n_row = mnz / 2 ;
+    Mlen = COLAMD_recommended (mnz, n_row, n) ;
+    M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
+    DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
+       n_row, n, mnz, (double) Mlen)) ;
+
+    if (!M)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+       (*release) ((void *) count) ;
+       (*release) ((void *) mark) ;
+       DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
+       return (FALSE) ;
+    }
+
+    k = 0 ;
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK)
+    {
+       /* Matrix is OK */
+       for (j = 0 ; j < n ; j++)
+       {
+           ASSERT (p [j+1] - p [j] >= 0) ;
+           for (pp = p [j] ; pp < p [j+1] ; pp++)
+           {
+               i = A [pp] ;
+               ASSERT (i >= 0 && i < n) ;
+               if (i > j)
+               {
+                   /* row k of M contains column indices i and j */
+                   M [count [i]++] = k ;
+                   M [count [j]++] = k ;
+                   k++ ;
+               }
+           }
+       }
+    }
+    else
+    {
+       /* Matrix is jumbled.  Do not add duplicates to M.  Unsorted cols OK. */
+       DEBUG0 (("symamd: Duplicates in A.\n")) ;
+       for (i = 0 ; i < n ; i++)
+       {
+           mark [i] = -1 ;
+       }
+       for (j = 0 ; j < n ; j++)
+       {
+           ASSERT (p [j+1] - p [j] >= 0) ;
+           for (pp = p [j] ; pp < p [j+1] ; pp++)
+           {
+               i = A [pp] ;
+               ASSERT (i >= 0 && i < n) ;
+               if (i > j && mark [i] != j)
+               {
+                   /* row k of M contains column indices i and j */
+                   M [count [i]++] = k ;
+                   M [count [j]++] = k ;
+                   k++ ;
+                   mark [i] = j ;
+               }
+           }
+       }
+       /* v2.4: free(mark) moved below */
+    }
+
+    /* count and mark no longer needed */
+    (*release) ((void *) count) ;
+    (*release) ((void *) mark) ;       /* v2.4: free (mark) moved here */
+    ASSERT (k == n_row) ;
+
+    /* === Adjust the knobs for M =========================================== */
+
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+       cknobs [i] = knobs [i] ;
+    }
+
+    /* there are no dense rows in M */
+    cknobs [COLAMD_DENSE_ROW] = -1 ;
+    cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
+
+    /* === Order the columns of M =========================================== */
+
+    /* v2.4: colamd cannot fail here, so the error check is removed */
+    (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
+
+    /* Note that the output permutation is now in perm */
+
+    /* === get the statistics for symamd from colamd ======================== */
+
+    /* a dense column in colamd means a dense row and col in symamd */
+    stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
+
+    /* === Free M =========================================================== */
+
+    (*release) ((void *) M) ;
+    DEBUG0 (("symamd: done.\n")) ;
+    return (TRUE) ;
+
+}
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd routine computes a column ordering Q of a sparse matrix
+    A such that the LU factorization P(AQ) = LU remains sparse, where P is
+    selected via partial pivoting.   The routine can also be viewed as
+    providing a permutation Q such that the Cholesky factorization
+    (AQ)'(AQ) = LL' remains sparse.
+*/
+
+PUBLIC Int COLAMD_MAIN         /* returns TRUE if successful, FALSE otherwise*/
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                 /* number of rows in A */
+    Int n_col,                 /* number of columns in A */
+    Int Alen,                  /* length of A */
+    Int A [],                  /* row indices of A */
+    Int p [],                  /* pointers to columns in A */
+    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS]   /* output statistics and error codes */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;                    /* loop index */
+    Int nnz ;                  /* nonzeros in A */
+    size_t Row_size ;          /* size of Row [], in integers */
+    size_t Col_size ;          /* size of Col [], in integers */
+    size_t need ;              /* minimum required length of A */
+    Colamd_Row *Row ;          /* pointer into A of Row [0..n_row] array */
+    Colamd_Col *Col ;          /* pointer into A of Col [0..n_col] array */
+    Int n_col2 ;               /* number of non-dense, non-empty columns */
+    Int n_row2 ;               /* number of non-dense, non-empty rows */
+    Int ngarbage ;             /* number of garbage collections performed */
+    Int max_deg ;              /* maximum row degree */
+    double default_knobs [COLAMD_KNOBS] ;      /* default knobs array */
+    Int aggressive ;           /* do aggressive absorption */
+    int ok ;
+
+#ifndef NDEBUG
+    colamd_get_debug ("colamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+       DEBUG0 (("colamd: stats not present\n")) ;
+       return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+       stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)            /* A is not present */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+       DEBUG0 (("colamd: A not present\n")) ;
+       return (FALSE) ;
+    }
+
+    if (!p)            /* p is not present */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+       DEBUG0 (("colamd: p not present\n")) ;
+       return (FALSE) ;
+    }
+
+    if (n_row < 0)     /* n_row must be >= 0 */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+       stats [COLAMD_INFO1] = n_row ;
+       DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
+       return (FALSE) ;
+    }
+
+    if (n_col < 0)     /* n_col must be >= 0 */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+       stats [COLAMD_INFO1] = n_col ;
+       DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
+       return (FALSE) ;
+    }
+
+    nnz = p [n_col] ;
+    if (nnz < 0)       /* nnz must be >= 0 */
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+       stats [COLAMD_INFO1] = nnz ;
+       DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
+       return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+       stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+       stats [COLAMD_INFO1] = p [0] ;
+       DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
+       return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+       COLAMD_set_defaults (default_knobs) ;
+       knobs = default_knobs ;
+    }
+
+    aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
+
+    /* === Allocate the Row and Col arrays from array A ===================== */
+
+    ok = TRUE ;
+    Col_size = COLAMD_C (n_col, &ok) ;     /* size of Col array of structs */
+    Row_size = COLAMD_R (n_row, &ok) ;     /* size of Row array of structs */
+
+    /* need = 2*nnz + n_col + Col_size + Row_size ; */
+    need = t_mult (nnz, 2, &ok) ;
+    need = t_add (need, n_col, &ok) ;
+    need = t_add (need, Col_size, &ok) ;
+    need = t_add (need, Row_size, &ok) ;
+
+    if (!ok || need > (size_t) Alen || need > Int_MAX)
+    {
+       /* not enough space in array A to perform the ordering */
+       stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+       stats [COLAMD_INFO1] = need ;
+       stats [COLAMD_INFO2] = Alen ;
+       DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
+       return (FALSE) ;
+    }
+
+    Alen -= Col_size + Row_size ;
+    Col = (Colamd_Col *) &A [Alen] ;
+    Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+    /* === Construct the row and column data structures ===================== */
+
+    if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+    {
+       /* input matrix is invalid */
+       DEBUG0 (("colamd: Matrix invalid\n")) ;
+       return (FALSE) ;
+    }
+
+    /* === Initialize scores, kill dense rows/columns ======================= */
+
+    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+       &n_row2, &n_col2, &max_deg) ;
+
+    /* === Order the supercolumns =========================================== */
+
+    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+       n_col2, max_deg, 2*nnz, aggressive) ;
+
+    /* === Order the non-principal columns ================================== */
+
+    order_children (n_col, Col, p) ;
+
+    /* === Return statistics in stats ======================================= */
+
+    stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
+    stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
+    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+    DEBUG0 (("colamd: done.\n")) ; 
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void COLAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("colamd", stats) ;
+}
+
+
+/* ========================================================================== */
+/* === symamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void SYMAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("symamd", stats) ;
+}
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+    Takes the column form of the matrix in A and creates the row form of the
+    matrix.  Also, row and column attributes are stored in the Col and Row
+    structs.  If the columns are un-sorted or contain duplicate row indices,
+    this routine will also sort and remove duplicate row indices from the
+    column form of the matrix.  Returns FALSE if the matrix is invalid,
+    TRUE otherwise.  Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols     /* returns TRUE if OK, or FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                 /* number of rows of A */
+    Int n_col,                 /* number of columns of A */
+    Colamd_Row Row [],         /* of size n_row+1 */
+    Colamd_Col Col [],         /* of size n_col+1 */
+    Int A [],                  /* row indices of A, of size Alen */
+    Int p [],                  /* pointers to columns in A, of size n_col+1 */
+    Int stats [COLAMD_STATS]   /* colamd statistics */ 
+)
+{
+    /* === Local variables ================================================== */
+
+    Int col ;                  /* a column index */
+    Int row ;                  /* a row index */
+    Int *cp ;                  /* a column pointer */
+    Int *cp_end ;              /* a pointer to the end of a column */
+    Int *rp ;                  /* a row pointer */
+    Int *rp_end ;              /* a pointer to the end of a row */
+    Int last_row ;             /* previous row */
+
+    /* === Initialize columns, and check column pointers ==================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+       Col [col].start = p [col] ;
+       Col [col].length = p [col+1] - p [col] ;
+
+       if (Col [col].length < 0)
+       {
+           /* column pointers must be non-decreasing */
+           stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+           stats [COLAMD_INFO1] = col ;
+           stats [COLAMD_INFO2] = Col [col].length ;
+           DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
+           return (FALSE) ;
+       }
+
+       Col [col].shared1.thickness = 1 ;
+       Col [col].shared2.score = 0 ;
+       Col [col].shared3.prev = EMPTY ;
+       Col [col].shared4.degree_next = EMPTY ;
+    }
+
+    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+    /* === Scan columns, compute row degrees, and check row indices ========= */
+
+    stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+       Row [row].length = 0 ;
+       Row [row].shared2.mark = -1 ;
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+       last_row = -1 ;
+
+       cp = &A [p [col]] ;
+       cp_end = &A [p [col+1]] ;
+
+       while (cp < cp_end)
+       {
+           row = *cp++ ;
+
+           /* make sure row indices within range */
+           if (row < 0 || row >= n_row)
+           {
+               stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+               stats [COLAMD_INFO1] = col ;
+               stats [COLAMD_INFO2] = row ;
+               stats [COLAMD_INFO3] = n_row ;
+               DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
+               return (FALSE) ;
+           }
+
+           if (row <= last_row || Row [row].shared2.mark == col)
+           {
+               /* row index are unsorted or repeated (or both), thus col */
+               /* is jumbled.  This is a notice, not an error condition. */
+               stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+               stats [COLAMD_INFO1] = col ;
+               stats [COLAMD_INFO2] = row ;
+               (stats [COLAMD_INFO3]) ++ ;
+               DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
+           }
+
+           if (Row [row].shared2.mark != col)
+           {
+               Row [row].length++ ;
+           }
+           else
+           {
+               /* this is a repeated entry in the column, */
+               /* it will be removed */
+               Col [col].length-- ;
+           }
+
+           /* mark the row as having been seen in this column */
+           Row [row].shared2.mark = col ;
+
+           last_row = row ;
+       }
+    }
+
+    /* === Compute row pointers ============================================= */
+
+    /* row form of the matrix starts directly after the column */
+    /* form of matrix in A */
+    Row [0].start = p [n_col] ;
+    Row [0].shared1.p = Row [0].start ;
+    Row [0].shared2.mark = -1 ;
+    for (row = 1 ; row < n_row ; row++)
+    {
+       Row [row].start = Row [row-1].start + Row [row-1].length ;
+       Row [row].shared1.p = Row [row].start ;
+       Row [row].shared2.mark = -1 ;
+    }
+
+    /* === Create row form ================================================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+       /* if cols jumbled, watch for repeated row indices */
+       for (col = 0 ; col < n_col ; col++)
+       {
+           cp = &A [p [col]] ;
+           cp_end = &A [p [col+1]] ;
+           while (cp < cp_end)
+           {
+               row = *cp++ ;
+               if (Row [row].shared2.mark != col)
+               {
+                   A [(Row [row].shared1.p)++] = col ;
+                   Row [row].shared2.mark = col ;
+               }
+           }
+       }
+    }
+    else
+    {
+       /* if cols not jumbled, we don't need the mark (this is faster) */
+       for (col = 0 ; col < n_col ; col++)
+       {
+           cp = &A [p [col]] ;
+           cp_end = &A [p [col+1]] ;
+           while (cp < cp_end)
+           {
+               A [(Row [*cp++].shared1.p)++] = col ;
+           }
+       }
+    }
+
+    /* === Clear the row marks and set row degrees ========================== */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+       Row [row].shared2.mark = 0 ;
+       Row [row].shared1.degree = Row [row].length ;
+    }
+
+    /* === See if we need to re-create columns ============================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+       DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
+
+#ifndef NDEBUG
+       /* make sure column lengths are correct */
+       for (col = 0 ; col < n_col ; col++)
+       {
+           p [col] = Col [col].length ;
+       }
+       for (row = 0 ; row < n_row ; row++)
+       {
+           rp = &A [Row [row].start] ;
+           rp_end = rp + Row [row].length ;
+           while (rp < rp_end)
+           {
+               p [*rp++]-- ;
+           }
+       }
+       for (col = 0 ; col < n_col ; col++)
+       {
+           ASSERT (p [col] == 0) ;
+       }
+       /* now p is all zero (different than when debugging is turned off) */
+#endif /* NDEBUG */
+
+       /* === Compute col pointers ========================================= */
+
+       /* col form of the matrix starts at A [0]. */
+       /* Note, we may have a gap between the col form and the row */
+       /* form if there were duplicate entries, if so, it will be */
+       /* removed upon the first garbage collection */
+       Col [0].start = 0 ;
+       p [0] = Col [0].start ;
+       for (col = 1 ; col < n_col ; col++)
+       {
+           /* note that the lengths here are for pruned columns, i.e. */
+           /* no duplicate row indices will exist for these columns */
+           Col [col].start = Col [col-1].start + Col [col-1].length ;
+           p [col] = Col [col].start ;
+       }
+
+       /* === Re-create col form =========================================== */
+
+       for (row = 0 ; row < n_row ; row++)
+       {
+           rp = &A [Row [row].start] ;
+           rp_end = rp + Row [row].length ;
+           while (rp < rp_end)
+           {
+               A [(p [*rp++])++] = row ;
+           }
+       }
+    }
+
+    /* === Done.  Matrix is not (or no longer) jumbled ====================== */
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+    Kills dense or empty columns and rows, calculates an initial score for
+    each column, and places all columns in the degree lists.  Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                 /* number of rows of A */
+    Int n_col,                 /* number of columns of A */
+    Colamd_Row Row [],         /* of size n_row+1 */
+    Colamd_Col Col [],         /* of size n_col+1 */
+    Int A [],                  /* column form and row form of A */
+    Int head [],               /* of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameters */
+    Int *p_n_row2,             /* number of non-dense, non-empty rows */
+    Int *p_n_col2,             /* number of non-dense, non-empty columns */
+    Int *p_max_deg             /* maximum row degree */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int c ;                    /* a column index */
+    Int r, row ;               /* a row index */
+    Int *cp ;                  /* a column pointer */
+    Int deg ;                  /* degree of a row or column */
+    Int *cp_end ;              /* a pointer to the end of a column */
+    Int *new_cp ;              /* new column pointer */
+    Int col_length ;           /* length of pruned column */
+    Int score ;                        /* current column score */
+    Int n_col2 ;               /* number of non-dense, non-empty columns */
+    Int n_row2 ;               /* number of non-dense, non-empty rows */
+    Int dense_row_count ;      /* remove rows with more entries than this */
+    Int dense_col_count ;      /* remove cols with more entries than this */
+    Int min_score ;            /* smallest column score */
+    Int max_deg ;              /* maximum row degree */
+    Int next_col ;             /* Used to add to degree list.*/
+
+#ifndef NDEBUG
+    Int debug_count ;          /* debug only. */
+#endif /* NDEBUG */
+
+    /* === Extract knobs ==================================================== */
+
+    /* Note: if knobs contains a NaN, this is undefined: */
+    if (knobs [COLAMD_DENSE_ROW] < 0)
+    {
+       /* only remove completely dense rows */
+       dense_row_count = n_col-1 ;
+    }
+    else
+    {
+       dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
+    }
+    if (knobs [COLAMD_DENSE_COL] < 0)
+    {
+       /* only remove completely dense columns */
+       dense_col_count = n_row-1 ;
+    }
+    else
+    {
+       dense_col_count =
+           DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
+    }
+
+    DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
+    max_deg = 0 ;
+    n_col2 = n_col ;
+    n_row2 = n_row ;
+
+    /* === Kill empty columns =============================================== */
+
+    /* Put the empty columns at the end in their natural order, so that LU */
+    /* factorization can proceed as far as possible. */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+       deg = Col [c].length ;
+       if (deg == 0)
+       {
+           /* this is a empty column, kill and order it last */
+           Col [c].shared2.order = --n_col2 ;
+           KILL_PRINCIPAL_COL (c) ;
+       }
+    }
+    DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense columns =============================================== */
+
+    /* Put the dense columns at the end, in their natural order */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+       /* skip any dead columns */
+       if (COL_IS_DEAD (c))
+       {
+           continue ;
+       }
+       deg = Col [c].length ;
+       if (deg > dense_col_count)
+       {
+           /* this is a dense column, kill and order it last */
+           Col [c].shared2.order = --n_col2 ;
+           /* decrement the row degrees */
+           cp = &A [Col [c].start] ;
+           cp_end = cp + Col [c].length ;
+           while (cp < cp_end)
+           {
+               Row [*cp++].shared1.degree-- ;
+           }
+           KILL_PRINCIPAL_COL (c) ;
+       }
+    }
+    DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense and empty rows ======================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+       deg = Row [r].shared1.degree ;
+       ASSERT (deg >= 0 && deg <= n_col) ;
+       if (deg > dense_row_count || deg == 0)
+       {
+           /* kill a dense or empty row */
+           KILL_ROW (r) ;
+           --n_row2 ;
+       }
+       else
+       {
+           /* keep track of max degree of remaining rows */
+           max_deg = MAX (max_deg, deg) ;
+       }
+    }
+    DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
+
+    /* === Compute initial column scores ==================================== */
+
+    /* At this point the row degrees are accurate.  They reflect the number */
+    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
+    /* Some "live" columns may contain only dead rows, however.  These are */
+    /* pruned in the code below. */
+
+    /* now find the initial matlab score for each column */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+       /* skip dead column */
+       if (COL_IS_DEAD (c))
+       {
+           continue ;
+       }
+       score = 0 ;
+       cp = &A [Col [c].start] ;
+       new_cp = cp ;
+       cp_end = cp + Col [c].length ;
+       while (cp < cp_end)
+       {
+           /* get a row */
+           row = *cp++ ;
+           /* skip if dead */
+           if (ROW_IS_DEAD (row))
+           {
+               continue ;
+           }
+           /* compact the column */
+           *new_cp++ = row ;
+           /* add row's external degree */
+           score += Row [row].shared1.degree - 1 ;
+           /* guard against integer overflow */
+           score = MIN (score, n_col) ;
+       }
+       /* determine pruned column length */
+       col_length = (Int) (new_cp - &A [Col [c].start]) ;
+       if (col_length == 0)
+       {
+           /* a newly-made null column (all rows in this col are "dense" */
+           /* and have already been killed) */
+           DEBUG2 (("Newly null killed: %d\n", c)) ;
+           Col [c].shared2.order = --n_col2 ;
+           KILL_PRINCIPAL_COL (c) ;
+       }
+       else
+       {
+           /* set column length and set score */
+           ASSERT (score >= 0) ;
+           ASSERT (score <= n_col) ;
+           Col [c].length = col_length ;
+           Col [c].shared2.score = score ;
+       }
+    }
+    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
+       n_col-n_col2)) ;
+
+    /* At this point, all empty rows and columns are dead.  All live columns */
+    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+    /* yet).  Rows may contain dead columns, but all live rows contain at */
+    /* least one live column. */
+
+#ifndef NDEBUG
+    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+    /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+    debug_count = 0 ;
+#endif /* NDEBUG */
+
+    /* clear the hash buckets */
+    for (c = 0 ; c <= n_col ; c++)
+    {
+       head [c] = EMPTY ;
+    }
+    min_score = n_col ;
+    /* place in reverse order, so low column indices are at the front */
+    /* of the lists.  This is to encourage natural tie-breaking */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+       /* only add principal columns to degree lists */
+       if (COL_IS_ALIVE (c))
+       {
+           DEBUG4 (("place %d score %d minscore %d ncol %d\n",
+               c, Col [c].shared2.score, min_score, n_col)) ;
+
+           /* === Add columns score to DList =============================== */
+
+           score = Col [c].shared2.score ;
+
+           ASSERT (min_score >= 0) ;
+           ASSERT (min_score <= n_col) ;
+           ASSERT (score >= 0) ;
+           ASSERT (score <= n_col) ;
+           ASSERT (head [score] >= EMPTY) ;
+
+           /* now add this column to dList at proper score location */
+           next_col = head [score] ;
+           Col [c].shared3.prev = EMPTY ;
+           Col [c].shared4.degree_next = next_col ;
+
+           /* if there already was a column with the same score, set its */
+           /* previous pointer to this new column */
+           if (next_col != EMPTY)
+           {
+               Col [next_col].shared3.prev = c ;
+           }
+           head [score] = c ;
+
+           /* see if this score is less than current min */
+           min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+           debug_count++ ;
+#endif /* NDEBUG */
+
+       }
+    }
+
+#ifndef NDEBUG
+    DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
+       debug_count, n_col, n_col-debug_count)) ;
+    ASSERT (debug_count == n_col2) ;
+    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+    /* === Return number of remaining columns, and max row degree =========== */
+
+    *p_n_col2 = n_col2 ;
+    *p_n_row2 = n_row2 ;
+    *p_max_deg = max_deg ;
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+    Order the principal columns of the supercolumn form of the matrix
+    (no supercolumns on input).  Uses a minimum approximate column minimum
+    degree ordering method.  Not user-callable.
+*/
+
+PRIVATE Int find_ordering      /* return the number of garbage collections */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                 /* number of rows of A */
+    Int n_col,                 /* number of columns of A */
+    Int Alen,                  /* size of A, 2*nnz + n_col or larger */
+    Colamd_Row Row [],         /* of size n_row+1 */
+    Colamd_Col Col [],         /* of size n_col+1 */
+    Int A [],                  /* column form and row form of A */
+    Int head [],               /* of size n_col+1 */
+    Int n_col2,                        /* Remaining columns to order */
+    Int max_deg,               /* Maximum row degree */
+    Int pfree,                 /* index of first free slot (2*nnz on entry) */
+    Int aggressive
+)
+{
+    /* === Local variables ================================================== */
+
+    Int k ;                    /* current pivot ordering step */
+    Int pivot_col ;            /* current pivot column */
+    Int *cp ;                  /* a column pointer */
+    Int *rp ;                  /* a row pointer */
+    Int pivot_row ;            /* current pivot row */
+    Int *new_cp ;              /* modified column pointer */
+    Int *new_rp ;              /* modified row pointer */
+    Int pivot_row_start ;      /* pointer to start of pivot row */
+    Int pivot_row_degree ;     /* number of columns in pivot row */
+    Int pivot_row_length ;     /* number of supercolumns in pivot row */
+    Int pivot_col_score ;      /* score of pivot column */
+    Int needed_memory ;                /* free space needed for pivot row */
+    Int *cp_end ;              /* pointer to the end of a column */
+    Int *rp_end ;              /* pointer to the end of a row */
+    Int row ;                  /* a row index */
+    Int col ;                  /* a column index */
+    Int max_score ;            /* maximum possible score */
+    Int cur_score ;            /* score of current column */
+    unsigned Int hash ;                /* hash value for supernode detection */
+    Int head_column ;          /* head of hash bucket */
+    Int first_col ;            /* first column in hash bucket */
+    Int tag_mark ;             /* marker value for mark array */
+    Int row_mark ;             /* Row [row].shared2.mark */
+    Int set_difference ;       /* set difference size of row with pivot row */
+    Int min_score ;            /* smallest column score */
+    Int col_thickness ;                /* "thickness" (no. of columns in a supercol) */
+    Int max_mark ;             /* maximum value of tag_mark */
+    Int pivot_col_thickness ;  /* number of columns represented by pivot col */
+    Int prev_col ;             /* Used by Dlist operations. */
+    Int next_col ;             /* Used by Dlist operations. */
+    Int ngarbage ;             /* number of garbage collections performed */
+
+#ifndef NDEBUG
+    Int debug_d ;              /* debug loop counter */
+    Int debug_step = 0 ;       /* debug loop counter */
+#endif /* NDEBUG */
+
+    /* === Initialization and clear mark ==================================== */
+
+    max_mark = INT_MAX - n_col ;       /* INT_MAX defined in <limits.h> */
+    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+    min_score = 0 ;
+    ngarbage = 0 ;
+    DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
+
+    /* === Order the columns ================================================ */
+
+    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+    {
+
+#ifndef NDEBUG
+       if (debug_step % 100 == 0)
+       {
+           DEBUG2 (("\n...       Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+       }
+       else
+       {
+           DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+       }
+       debug_step++ ;
+       debug_deg_lists (n_row, n_col, Row, Col, head,
+               min_score, n_col2-k, max_deg) ;
+       debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+       /* === Select pivot column, and order it ============================ */
+
+       /* make sure degree list isn't empty */
+       ASSERT (min_score >= 0) ;
+       ASSERT (min_score <= n_col) ;
+       ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+       for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+       {
+           ASSERT (head [debug_d] == EMPTY) ;
+       }
+#endif /* NDEBUG */
+
+       /* get pivot column from head of minimum degree list */
+       while (head [min_score] == EMPTY && min_score < n_col)
+       {
+           min_score++ ;
+       }
+       pivot_col = head [min_score] ;
+       ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+       next_col = Col [pivot_col].shared4.degree_next ;
+       head [min_score] = next_col ;
+       if (next_col != EMPTY)
+       {
+           Col [next_col].shared3.prev = EMPTY ;
+       }
+
+       ASSERT (COL_IS_ALIVE (pivot_col)) ;
+
+       /* remember score for defrag check */
+       pivot_col_score = Col [pivot_col].shared2.score ;
+
+       /* the pivot column is the kth column in the pivot order */
+       Col [pivot_col].shared2.order = k ;
+
+       /* increment order count by column thickness */
+       pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+       k += pivot_col_thickness ;
+       ASSERT (pivot_col_thickness > 0) ;
+       DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
+
+       /* === Garbage_collection, if necessary ============================= */
+
+       needed_memory = MIN (pivot_col_score, n_col - k) ;
+       if (pfree + needed_memory >= Alen)
+       {
+           pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+           ngarbage++ ;
+           /* after garbage collection we will have enough */
+           ASSERT (pfree + needed_memory < Alen) ;
+           /* garbage collection has wiped out the Row[].shared2.mark array */
+           tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+           debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+       }
+
+       /* === Compute pivot row pattern ==================================== */
+
+       /* get starting location for this new merged row */
+       pivot_row_start = pfree ;
+
+       /* initialize new row counts to zero */
+       pivot_row_degree = 0 ;
+
+       /* tag pivot column as having been visited so it isn't included */
+       /* in merged pivot row */
+       Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+       /* pivot row is the union of all rows in the pivot column pattern */
+       cp = &A [Col [pivot_col].start] ;
+       cp_end = cp + Col [pivot_col].length ;
+       while (cp < cp_end)
+       {
+           /* get a row */
+           row = *cp++ ;
+           DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
+           /* skip if row is dead */
+           if (ROW_IS_ALIVE (row))
+           {
+               rp = &A [Row [row].start] ;
+               rp_end = rp + Row [row].length ;
+               while (rp < rp_end)
+               {
+                   /* get a column */
+                   col = *rp++ ;
+                   /* add the column, if alive and untagged */
+                   col_thickness = Col [col].shared1.thickness ;
+                   if (col_thickness > 0 && COL_IS_ALIVE (col))
+                   {
+                       /* tag column in pivot row */
+                       Col [col].shared1.thickness = -col_thickness ;
+                       ASSERT (pfree < Alen) ;
+                       /* place column in pivot row */
+                       A [pfree++] = col ;
+                       pivot_row_degree += col_thickness ;
+                   }
+               }
+           }
+       }
+
+       /* clear tag on pivot column */
+       Col [pivot_col].shared1.thickness = pivot_col_thickness ;
+       max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+       DEBUG3 (("check2\n")) ;
+       debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+       /* === Kill all rows used to construct pivot row ==================== */
+
+       /* also kill pivot row, temporarily */
+       cp = &A [Col [pivot_col].start] ;
+       cp_end = cp + Col [pivot_col].length ;
+       while (cp < cp_end)
+       {
+           /* may be killing an already dead row */
+           row = *cp++ ;
+           DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
+           KILL_ROW (row) ;
+       }
+
+       /* === Select a row index to use as the new pivot row =============== */
+
+       pivot_row_length = pfree - pivot_row_start ;
+       if (pivot_row_length > 0)
+       {
+           /* pick the "pivot" row arbitrarily (first row in col) */
+           pivot_row = A [Col [pivot_col].start] ;
+           DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
+       }
+       else
+       {
+           /* there is no pivot row, since it is of zero length */
+           pivot_row = EMPTY ;
+           ASSERT (pivot_row_length == 0) ;
+       }
+       ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+       /* === Approximate degree computation =============================== */
+
+       /* Here begins the computation of the approximate degree.  The column */
+       /* score is the sum of the pivot row "length", plus the size of the */
+       /* set differences of each row in the column minus the pattern of the */
+       /* pivot row itself.  The column ("thickness") itself is also */
+       /* excluded from the column score (we thus use an approximate */
+       /* external degree). */
+
+       /* The time taken by the following code (compute set differences, and */
+       /* add them up) is proportional to the size of the data structure */
+       /* being scanned - that is, the sum of the sizes of each column in */
+       /* the pivot row.  Thus, the amortized time to compute a column score */
+       /* is proportional to the size of that column (where size, in this */
+       /* context, is the column "length", or the number of row indices */
+       /* in that column).  The number of row indices in a column is */
+       /* monotonically non-decreasing, from the length of the original */
+       /* column on input to colamd. */
+
+       /* === Compute set differences ====================================== */
+
+       DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+       /* pivot row is currently dead - it will be revived later. */
+
+       DEBUG3 (("Pivot row: ")) ;
+       /* for each column in pivot row */
+       rp = &A [pivot_row_start] ;
+       rp_end = rp + pivot_row_length ;
+       while (rp < rp_end)
+       {
+           col = *rp++ ;
+           ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+           DEBUG3 (("Col: %d\n", col)) ;
+
+           /* clear tags used to construct pivot row pattern */
+           col_thickness = -Col [col].shared1.thickness ;
+           ASSERT (col_thickness > 0) ;
+           Col [col].shared1.thickness = col_thickness ;
+
+           /* === Remove column from degree list =========================== */
+
+           cur_score = Col [col].shared2.score ;
+           prev_col = Col [col].shared3.prev ;
+           next_col = Col [col].shared4.degree_next ;
+           ASSERT (cur_score >= 0) ;
+           ASSERT (cur_score <= n_col) ;
+           ASSERT (cur_score >= EMPTY) ;
+           if (prev_col == EMPTY)
+           {
+               head [cur_score] = next_col ;
+           }
+           else
+           {
+               Col [prev_col].shared4.degree_next = next_col ;
+           }
+           if (next_col != EMPTY)
+           {
+               Col [next_col].shared3.prev = prev_col ;
+           }
+
+           /* === Scan the column ========================================== */
+
+           cp = &A [Col [col].start] ;
+           cp_end = cp + Col [col].length ;
+           while (cp < cp_end)
+           {
+               /* get a row */
+               row = *cp++ ;
+               row_mark = Row [row].shared2.mark ;
+               /* skip if dead */
+               if (ROW_IS_MARKED_DEAD (row_mark))
+               {
+                   continue ;
+               }
+               ASSERT (row != pivot_row) ;
+               set_difference = row_mark - tag_mark ;
+               /* check if the row has been seen yet */
+               if (set_difference < 0)
+               {
+                   ASSERT (Row [row].shared1.degree <= max_deg) ;
+                   set_difference = Row [row].shared1.degree ;
+               }
+               /* subtract column thickness from this row's set difference */
+               set_difference -= col_thickness ;
+               ASSERT (set_difference >= 0) ;
+               /* absorb this row if the set difference becomes zero */
+               if (set_difference == 0 && aggressive)
+               {
+                   DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
+                   KILL_ROW (row) ;
+               }
+               else
+               {
+                   /* save the new mark */
+                   Row [row].shared2.mark = set_difference + tag_mark ;
+               }
+           }
+       }
+
+#ifndef NDEBUG
+       debug_deg_lists (n_row, n_col, Row, Col, head,
+               min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+       /* === Add up set differences for each column ======================= */
+
+       DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+       /* for each column in pivot row */
+       rp = &A [pivot_row_start] ;
+       rp_end = rp + pivot_row_length ;
+       while (rp < rp_end)
+       {
+           /* get a column */
+           col = *rp++ ;
+           ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+           hash = 0 ;
+           cur_score = 0 ;
+           cp = &A [Col [col].start] ;
+           /* compact the column */
+           new_cp = cp ;
+           cp_end = cp + Col [col].length ;
+
+           DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
+
+           while (cp < cp_end)
+           {
+               /* get a row */
+               row = *cp++ ;
+               ASSERT(row >= 0 && row < n_row) ;
+               row_mark = Row [row].shared2.mark ;
+               /* skip if dead */
+               if (ROW_IS_MARKED_DEAD (row_mark))
+               {
+                   DEBUG4 ((" Row %d, dead\n", row)) ;
+                   continue ;
+               }
+               DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
+               ASSERT (row_mark >= tag_mark) ;
+               /* compact the column */
+               *new_cp++ = row ;
+               /* compute hash function */
+               hash += row ;
+               /* add set difference */
+               cur_score += row_mark - tag_mark ;
+               /* integer overflow... */
+               cur_score = MIN (cur_score, n_col) ;
+           }
+
+           /* recompute the column's length */
+           Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+           /* === Further mass elimination ================================= */
+
+           if (Col [col].length == 0)
+           {
+               DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
+               /* nothing left but the pivot row in this column */
+               KILL_PRINCIPAL_COL (col) ;
+               pivot_row_degree -= Col [col].shared1.thickness ;
+               ASSERT (pivot_row_degree >= 0) ;
+               /* order it */
+               Col [col].shared2.order = k ;
+               /* increment order count by column thickness */
+               k += Col [col].shared1.thickness ;
+           }
+           else
+           {
+               /* === Prepare for supercolumn detection ==================== */
+
+               DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
+
+               /* save score so far */
+               Col [col].shared2.score = cur_score ;
+
+               /* add column to hash table, for supercolumn detection */
+               hash %= n_col + 1 ;
+
+               DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
+               ASSERT (((Int) hash) <= n_col) ;
+
+               head_column = head [hash] ;
+               if (head_column > EMPTY)
+               {
+                   /* degree list "hash" is non-empty, use prev (shared3) of */
+                   /* first column in degree list as head of hash bucket */
+                   first_col = Col [head_column].shared3.headhash ;
+                   Col [head_column].shared3.headhash = col ;
+               }
+               else
+               {
+                   /* degree list "hash" is empty, use head as hash bucket */
+                   first_col = - (head_column + 2) ;
+                   head [hash] = - (col + 2) ;
+               }
+               Col [col].shared4.hash_next = first_col ;
+
+               /* save hash function in Col [col].shared3.hash */
+               Col [col].shared3.hash = (Int) hash ;
+               ASSERT (COL_IS_ALIVE (col)) ;
+           }
+       }
+
+       /* The approximate external column degree is now computed.  */
+
+       /* === Supercolumn detection ======================================== */
+
+       DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+       detect_super_cols (
+
+#ifndef NDEBUG
+               n_col, Row,
+#endif /* NDEBUG */
+
+               Col, A, head, pivot_row_start, pivot_row_length) ;
+
+       /* === Kill the pivotal column ====================================== */
+
+       KILL_PRINCIPAL_COL (pivot_col) ;
+
+       /* === Clear mark =================================================== */
+
+       tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+       DEBUG3 (("check3\n")) ;
+       debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+       /* === Finalize the new pivot row, and column scores ================ */
+
+       DEBUG3 (("** Finalize scores phase. **\n")) ;
+
+       /* for each column in pivot row */
+       rp = &A [pivot_row_start] ;
+       /* compact the pivot row */
+       new_rp = rp ;
+       rp_end = rp + pivot_row_length ;
+       while (rp < rp_end)
+       {
+           col = *rp++ ;
+           /* skip dead columns */
+           if (COL_IS_DEAD (col))
+           {
+               continue ;
+           }
+           *new_rp++ = col ;
+           /* add new pivot row to column */
+           A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+           /* retrieve score so far and add on pivot row's degree. */
+           /* (we wait until here for this in case the pivot */
+           /* row's degree was reduced due to mass elimination). */
+           cur_score = Col [col].shared2.score + pivot_row_degree ;
+
+           /* calculate the max possible score as the number of */
+           /* external columns minus the 'k' value minus the */
+           /* columns thickness */
+           max_score = n_col - k - Col [col].shared1.thickness ;
+
+           /* make the score the external degree of the union-of-rows */
+           cur_score -= Col [col].shared1.thickness ;
+
+           /* make sure score is less or equal than the max score */
+           cur_score = MIN (cur_score, max_score) ;
+           ASSERT (cur_score >= 0) ;
+
+           /* store updated score */
+           Col [col].shared2.score = cur_score ;
+
+           /* === Place column back in degree list ========================= */
+
+           ASSERT (min_score >= 0) ;
+           ASSERT (min_score <= n_col) ;
+           ASSERT (cur_score >= 0) ;
+           ASSERT (cur_score <= n_col) ;
+           ASSERT (head [cur_score] >= EMPTY) ;
+           next_col = head [cur_score] ;
+           Col [col].shared4.degree_next = next_col ;
+           Col [col].shared3.prev = EMPTY ;
+           if (next_col != EMPTY)
+           {
+               Col [next_col].shared3.prev = col ;
+           }
+           head [cur_score] = col ;
+
+           /* see if this score is less than current min */
+           min_score = MIN (min_score, cur_score) ;
+
+       }
+
+#ifndef NDEBUG
+       debug_deg_lists (n_row, n_col, Row, Col, head,
+               min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+       /* === Resurrect the new pivot row ================================== */
+
+       if (pivot_row_degree > 0)
+       {
+           /* update pivot row length to reflect any cols that were killed */
+           /* during super-col detection and mass elimination */
+           Row [pivot_row].start  = pivot_row_start ;
+           Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+           ASSERT (Row [pivot_row].length > 0) ;
+           Row [pivot_row].shared1.degree = pivot_row_degree ;
+           Row [pivot_row].shared2.mark = 0 ;
+           /* pivot row is no longer dead */
+
+           DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
+                       pivot_row, pivot_row_degree)) ;
+       }
+    }
+
+    /* === All principal columns have now been ordered ====================== */
+
+    return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children ======================================================= */
+/* ========================================================================== */
+
+/*
+    The find_ordering routine has ordered all of the principal columns (the
+    representatives of the supercolumns).  The non-principal columns have not
+    yet been ordered.  This routine orders those columns by walking up the
+    parent tree (a column is a child of the column which absorbed it).  The
+    final permutation vector is then placed in p [0 ... n_col-1], with p [0]
+    being the first column, and p [n_col-1] being the last.  It doesn't look
+    like it at first glance, but be assured that this routine takes time linear
+    in the number of columns.  Although not immediately obvious, the time
+    taken by this routine is O (n_col), that is, linear in the number of
+    columns.  Not user-callable.
+*/
+
+PRIVATE void order_children
+(
+    /* === Parameters ======================================================= */
+
+    Int n_col,                 /* number of columns of A */
+    Colamd_Col Col [],         /* of size n_col+1 */
+    Int p []                   /* p [0 ... n_col-1] is the column permutation*/
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;                    /* loop counter for all columns */
+    Int c ;                    /* column index */
+    Int parent ;               /* index of column's parent */
+    Int order ;                        /* column's order */
+
+    /* === Order each non-principal column ================================== */
+
+    for (i = 0 ; i < n_col ; i++)
+    {
+       /* find an un-ordered non-principal column */
+       ASSERT (COL_IS_DEAD (i)) ;
+       if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
+       {
+           parent = i ;
+           /* once found, find its principal parent */
+           do
+           {
+               parent = Col [parent].shared1.parent ;
+           } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
+
+           /* now, order all un-ordered non-principal columns along path */
+           /* to this parent.  collapse tree at the same time */
+           c = i ;
+           /* get order of parent */
+           order = Col [parent].shared2.order ;
+
+           do
+           {
+               ASSERT (Col [c].shared2.order == EMPTY) ;
+
+               /* order this column */
+               Col [c].shared2.order = order++ ;
+               /* collaps tree */
+               Col [c].shared1.parent = parent ;
+
+               /* get immediate parent of this column */
+               c = Col [c].shared1.parent ;
+
+               /* continue until we hit an ordered column.  There are */
+               /* guarranteed not to be anymore unordered columns */
+               /* above an ordered column */
+           } while (Col [c].shared2.order == EMPTY) ;
+
+           /* re-order the super_col parent to largest order for this group */
+           Col [parent].shared2.order = order ;
+       }
+    }
+
+    /* === Generate the permutation ========================================= */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+       p [Col [c].shared2.order] = c ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+    Detects supercolumns by finding matches between columns in the hash buckets.
+    Check amongst columns in the set A [row_start ... row_start + row_length-1].
+    The columns under consideration are currently *not* in the degree lists,
+    and have already been placed in the hash buckets.
+
+    The hash bucket for columns whose hash function is equal to h is stored
+    as follows:
+
+       if head [h] is >= 0, then head [h] contains a degree list, so:
+
+               head [h] is the first column in degree bucket h.
+               Col [head [h]].headhash gives the first column in hash bucket h.
+
+       otherwise, the degree list is empty, and:
+
+               -(head [h] + 2) is the first column in hash bucket h.
+
+    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+    column" pointer.  Col [c].shared3.hash is used instead as the hash number
+    for that column.  The value of Col [c].shared4.hash_next is the next column
+    in the same hash bucket.
+
+    Assuming no, or "few" hash collisions, the time taken by this routine is
+    linear in the sum of the sizes (lengths) of each column whose score has
+    just been computed in the approximate degree computation.
+    Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+    /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+    /* these two parameters are only needed when debugging is enabled: */
+    Int n_col,                 /* number of columns of A */
+    Colamd_Row Row [],         /* of size n_row+1 */
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],         /* of size n_col+1 */
+    Int A [],                  /* row indices of A */
+    Int head [],               /* head of degree lists and hash buckets */
+    Int row_start,             /* pointer to set of columns to check */
+    Int row_length             /* number of columns to check */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int hash ;                 /* hash value for a column */
+    Int *rp ;                  /* pointer to a row */
+    Int c ;                    /* a column index */
+    Int super_c ;              /* column index of the column to absorb into */
+    Int *cp1 ;                 /* column pointer for column super_c */
+    Int *cp2 ;                 /* column pointer for column c */
+    Int length ;               /* length of column super_c */
+    Int prev_c ;               /* column preceding c in hash bucket */
+    Int i ;                    /* loop counter */
+    Int *rp_end ;              /* pointer to the end of the row */
+    Int col ;                  /* a column index in the row to check */
+    Int head_column ;          /* first column in hash bucket or degree list */
+    Int first_col ;            /* first column in hash bucket */
+
+    /* === Consider each column in the row ================================== */
+
+    rp = &A [row_start] ;
+    rp_end = rp + row_length ;
+    while (rp < rp_end)
+    {
+       col = *rp++ ;
+       if (COL_IS_DEAD (col))
+       {
+           continue ;
+       }
+
+       /* get hash number for this column */
+       hash = Col [col].shared3.hash ;
+       ASSERT (hash <= n_col) ;
+
+       /* === Get the first column in this hash bucket ===================== */
+
+       head_column = head [hash] ;
+       if (head_column > EMPTY)
+       {
+           first_col = Col [head_column].shared3.headhash ;
+       }
+       else
+       {
+           first_col = - (head_column + 2) ;
+       }
+
+       /* === Consider each column in the hash bucket ====================== */
+
+       for (super_c = first_col ; super_c != EMPTY ;
+           super_c = Col [super_c].shared4.hash_next)
+       {
+           ASSERT (COL_IS_ALIVE (super_c)) ;
+           ASSERT (Col [super_c].shared3.hash == hash) ;
+           length = Col [super_c].length ;
+
+           /* prev_c is the column preceding column c in the hash bucket */
+           prev_c = super_c ;
+
+           /* === Compare super_c with all columns after it ================ */
+
+           for (c = Col [super_c].shared4.hash_next ;
+                c != EMPTY ; c = Col [c].shared4.hash_next)
+           {
+               ASSERT (c != super_c) ;
+               ASSERT (COL_IS_ALIVE (c)) ;
+               ASSERT (Col [c].shared3.hash == hash) ;
+
+               /* not identical if lengths or scores are different */
+               if (Col [c].length != length ||
+                   Col [c].shared2.score != Col [super_c].shared2.score)
+               {
+                   prev_c = c ;
+                   continue ;
+               }
+
+               /* compare the two columns */
+               cp1 = &A [Col [super_c].start] ;
+               cp2 = &A [Col [c].start] ;
+
+               for (i = 0 ; i < length ; i++)
+               {
+                   /* the columns are "clean" (no dead rows) */
+                   ASSERT (ROW_IS_ALIVE (*cp1))  ;
+                   ASSERT (ROW_IS_ALIVE (*cp2))  ;
+                   /* row indices will same order for both supercols, */
+                   /* no gather scatter nessasary */
+                   if (*cp1++ != *cp2++)
+                   {
+                       break ;
+                   }
+               }
+
+               /* the two columns are different if the for-loop "broke" */
+               if (i != length)
+               {
+                   prev_c = c ;
+                   continue ;
+               }
+
+               /* === Got it!  two columns are identical =================== */
+
+               ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+               Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+               Col [c].shared1.parent = super_c ;
+               KILL_NON_PRINCIPAL_COL (c) ;
+               /* order c later, in order_children() */
+               Col [c].shared2.order = EMPTY ;
+               /* remove c from hash bucket */
+               Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+           }
+       }
+
+       /* === Empty this hash bucket ======================================= */
+
+       if (head_column > EMPTY)
+       {
+           /* corresponding degree list "hash" is not empty */
+           Col [head_column].shared3.headhash = EMPTY ;
+       }
+       else
+       {
+           /* corresponding degree list "hash" is empty */
+           head [hash] = EMPTY ;
+       }
+    }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+    Defragments and compacts columns and rows in the workspace A.  Used when
+    all avaliable memory has been used while performing row merging.  Returns
+    the index of the first free position in A, after garbage collection.  The
+    time taken by this routine is linear is the size of the array A, which is
+    itself linear in the number of nonzeros in the input matrix.
+    Not user-callable.
+*/
+
+PRIVATE Int garbage_collection  /* returns the new value of pfree */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,                 /* number of rows */
+    Int n_col,                 /* number of columns */
+    Colamd_Row Row [],         /* row info */
+    Colamd_Col Col [],         /* column info */
+    Int A [],                  /* A [0 ... Alen-1] holds the matrix */
+    Int *pfree                 /* &A [0] ... pfree is in use */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *psrc ;                        /* source pointer */
+    Int *pdest ;               /* destination pointer */
+    Int j ;                    /* counter */
+    Int r ;                    /* a row index */
+    Int c ;                    /* a column index */
+    Int length ;               /* length of a row or column */
+
+#ifndef NDEBUG
+    Int debug_rows ;
+    DEBUG2 (("Defrag..\n")) ;
+    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+    debug_rows = 0 ;
+#endif /* NDEBUG */
+
+    /* === Defragment the columns =========================================== */
+
+    pdest = &A[0] ;
+    for (c = 0 ; c < n_col ; c++)
+    {
+       if (COL_IS_ALIVE (c))
+       {
+           psrc = &A [Col [c].start] ;
+
+           /* move and compact the column */
+           ASSERT (pdest <= psrc) ;
+           Col [c].start = (Int) (pdest - &A [0]) ;
+           length = Col [c].length ;
+           for (j = 0 ; j < length ; j++)
+           {
+               r = *psrc++ ;
+               if (ROW_IS_ALIVE (r))
+               {
+                   *pdest++ = r ;
+               }
+           }
+           Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+       }
+    }
+
+    /* === Prepare to defragment the rows =================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+       if (ROW_IS_DEAD (r) || (Row [r].length == 0))
+       {
+           /* This row is already dead, or is of zero length.  Cannot compact
+            * a row of zero length, so kill it.  NOTE: in the current version,
+            * there are no zero-length live rows.  Kill the row (for the first
+            * time, or again) just to be safe. */
+           KILL_ROW (r) ;
+       }
+       else
+       {
+           /* save first column index in Row [r].shared2.first_column */
+           psrc = &A [Row [r].start] ;
+           Row [r].shared2.first_column = *psrc ;
+           ASSERT (ROW_IS_ALIVE (r)) ;
+           /* flag the start of the row with the one's complement of row */
+           *psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+           debug_rows++ ;
+#endif /* NDEBUG */
+       }
+    }
+
+    /* === Defragment the rows ============================================== */
+
+    psrc = pdest ;
+    while (psrc < pfree)
+    {
+       /* find a negative number ... the start of a row */
+       if (*psrc++ < 0)
+       {
+           psrc-- ;
+           /* get the row index */
+           r = ONES_COMPLEMENT (*psrc) ;
+           ASSERT (r >= 0 && r < n_row) ;
+           /* restore first column index */
+           *psrc = Row [r].shared2.first_column ;
+           ASSERT (ROW_IS_ALIVE (r)) ;
+           ASSERT (Row [r].length > 0) ;
+           /* move and compact the row */
+           ASSERT (pdest <= psrc) ;
+           Row [r].start = (Int) (pdest - &A [0]) ;
+           length = Row [r].length ;
+           for (j = 0 ; j < length ; j++)
+           {
+               c = *psrc++ ;
+               if (COL_IS_ALIVE (c))
+               {
+                   *pdest++ = c ;
+               }
+           }
+           Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+           ASSERT (Row [r].length > 0) ;
+#ifndef NDEBUG
+           debug_rows-- ;
+#endif /* NDEBUG */
+       }
+    }
+    /* ensure we found all the rows */
+    ASSERT (debug_rows == 0) ;
+
+    /* === Return the new value of pfree ==================================== */
+
+    return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Clears the Row [].shared2.mark array, and returns the new tag_mark.
+    Return value is the new tag_mark.  Not user-callable.
+*/
+
+PRIVATE Int clear_mark /* return the new value for tag_mark */
+(
+    /* === Parameters ======================================================= */
+
+    Int tag_mark,      /* new value of tag_mark */
+    Int max_mark,      /* max allowed value of tag_mark */
+
+    Int n_row,         /* number of rows in A */
+    Colamd_Row Row []  /* Row [0 ... n_row-1].shared2.mark is set to zero */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    if (tag_mark <= 0 || tag_mark >= max_mark)
+    {
+       for (r = 0 ; r < n_row ; r++)
+       {
+           if (ROW_IS_ALIVE (r))
+           {
+               Row [r].shared2.mark = 0 ;
+           }
+       }
+       tag_mark = 1 ;
+    }
+
+    return (tag_mark) ;
+}
+
+
+/* ========================================================================== */
+/* === print_report ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+)
+{
+
+    Int i1, i2, i3 ;
+
+    PRINTF (("\n%s version %d.%d, %s: ", method,
+           COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
+
+    if (!stats)
+    {
+       PRINTF (("No statistics available.\n")) ;
+       return ;
+    }
+
+    i1 = stats [COLAMD_INFO1] ;
+    i2 = stats [COLAMD_INFO2] ;
+    i3 = stats [COLAMD_INFO3] ;
+
+    if (stats [COLAMD_STATUS] >= 0)
+    {
+       PRINTF (("OK.  ")) ;
+    }
+    else
+    {
+       PRINTF (("ERROR.  ")) ;
+    }
+
+    switch (stats [COLAMD_STATUS])
+    {
+
+       case COLAMD_OK_BUT_JUMBLED:
+
+           PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
+
+           PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
+           method, i3)) ;
+
+           PRINTF(("%s: last seen duplicate or out-of-order row index:   %d\n",
+           method, INDEX (i2))) ;
+
+           PRINTF(("%s: last seen in column:                             %d",
+           method, INDEX (i1))) ;
+
+           /* no break - fall through to next case instead */
+
+       case COLAMD_OK:
+
+           PRINTF(("\n")) ;
+
+           PRINTF(("%s: number of dense or empty rows ignored:           %d\n",
+           method, stats [COLAMD_DENSE_ROW])) ;
+
+           PRINTF(("%s: number of dense or empty columns ignored:        %d\n",
+           method, stats [COLAMD_DENSE_COL])) ;
+
+           PRINTF(("%s: number of garbage collections performed:         %d\n",
+           method, stats [COLAMD_DEFRAG_COUNT])) ;
+           break ;
+
+       case COLAMD_ERROR_A_not_present:
+
+           PRINTF(("Array A (row indices of matrix) not present.\n")) ;
+           break ;
+
+       case COLAMD_ERROR_p_not_present:
+
+           PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
+           break ;
+
+       case COLAMD_ERROR_nrow_negative:
+
+           PRINTF(("Invalid number of rows (%d).\n", i1)) ;
+           break ;
+
+       case COLAMD_ERROR_ncol_negative:
+
+           PRINTF(("Invalid number of columns (%d).\n", i1)) ;
+           break ;
+
+       case COLAMD_ERROR_nnz_negative:
+
+           PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
+           break ;
+
+       case COLAMD_ERROR_p0_nonzero:
+
+           PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
+           break ;
+
+       case COLAMD_ERROR_A_too_small:
+
+           PRINTF(("Array A too small.\n")) ;
+           PRINTF(("        Need Alen >= %d, but given only Alen = %d.\n",
+           i1, i2)) ;
+           break ;
+
+       case COLAMD_ERROR_col_length_negative:
+
+           PRINTF
+           (("Column %d has a negative number of nonzero entries (%d).\n",
+           INDEX (i1), i2)) ;
+           break ;
+
+       case COLAMD_ERROR_row_index_out_of_bounds:
+
+           PRINTF
+           (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
+           INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
+           break ;
+
+       case COLAMD_ERROR_out_of_memory:
+
+           PRINTF(("Out of memory.\n")) ;
+           break ;
+
+       /* v2.4: internal-error case deleted */
+    }
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+    At this point, all empty rows and columns are dead.  All live columns
+    are "clean" (containing no dead rows) and simplicial (no supercolumns
+    yet).  Rows may contain dead columns, but all live rows contain at
+    least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+    Int c ;
+    Int *cp ;
+    Int *cp_end ;
+    Int len ;
+    Int score ;
+    Int r ;
+    Int *rp ;
+    Int *rp_end ;
+    Int deg ;
+
+    /* === Check A, Row, and Col ============================================ */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+       if (COL_IS_ALIVE (c))
+       {
+           len = Col [c].length ;
+           score = Col [c].shared2.score ;
+           DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
+           ASSERT (len > 0) ;
+           ASSERT (score >= 0) ;
+           ASSERT (Col [c].shared1.thickness == 1) ;
+           cp = &A [Col [c].start] ;
+           cp_end = cp + len ;
+           while (cp < cp_end)
+           {
+               r = *cp++ ;
+               ASSERT (ROW_IS_ALIVE (r)) ;
+           }
+       }
+       else
+       {
+           i = Col [c].shared2.order ;
+           ASSERT (i >= n_col2 && i < n_col) ;
+       }
+    }
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+       if (ROW_IS_ALIVE (r))
+       {
+           i = 0 ;
+           len = Row [r].length ;
+           deg = Row [r].shared1.degree ;
+           ASSERT (len > 0) ;
+           ASSERT (deg > 0) ;
+           rp = &A [Row [r].start] ;
+           rp_end = rp + len ;
+           while (rp < rp_end)
+           {
+               c = *rp++ ;
+               if (COL_IS_ALIVE (c))
+               {
+                   i++ ;
+               }
+           }
+           ASSERT (i > 0) ;
+       }
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+    Prints the contents of the degree lists.  Counts the number of columns
+    in the degree list and compares it to the total it should have.  Also
+    checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+)
+{
+    /* === Local variables ================================================== */
+
+    Int deg ;
+    Int col ;
+    Int have ;
+    Int row ;
+
+    /* === Check the degree lists =========================================== */
+
+    if (n_col > 10000 && colamd_debug <= 0)
+    {
+       return ;
+    }
+    have = 0 ;
+    DEBUG4 (("Degree lists: %d\n", min_score)) ;
+    for (deg = 0 ; deg <= n_col ; deg++)
+    {
+       col = head [deg] ;
+       if (col == EMPTY)
+       {
+           continue ;
+       }
+       DEBUG4 (("%d:", deg)) ;
+       while (col != EMPTY)
+       {
+           DEBUG4 ((" %d", col)) ;
+           have += Col [col].shared1.thickness ;
+           ASSERT (COL_IS_ALIVE (col)) ;
+           col = Col [col].shared4.degree_next ;
+       }
+       DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("should %d have %d\n", should, have)) ;
+    ASSERT (should == have) ;
+
+    /* === Check the row degrees ============================================ */
+
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+       return ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+       if (ROW_IS_ALIVE (row))
+       {
+           ASSERT (Row [row].shared1.degree <= max_deg) ;
+       }
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Ensures that the tag_mark is less that the maximum and also ensures that
+    each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    /* === Check the Row marks ============================================== */
+
+    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+       return ;
+    }
+    for (r = 0 ; r < n_row ; r++)
+    {
+       ASSERT (Row [r].shared2.mark < tag_mark) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+    Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+    Int c ;
+    Int *rp ;
+    Int *rp_end ;
+    Int *cp ;
+    Int *cp_end ;
+
+    /* === Dump the rows and columns of the matrix ========================== */
+
+    if (colamd_debug < 3)
+    {
+       return ;
+    }
+    DEBUG3 (("DUMP MATRIX:\n")) ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+       DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+       if (ROW_IS_DEAD (r))
+       {
+           continue ;
+       }
+       DEBUG3 (("start %d length %d degree %d\n",
+               Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
+       rp = &A [Row [r].start] ;
+       rp_end = rp + Row [r].length ;
+       while (rp < rp_end)
+       {
+           c = *rp++ ;
+           DEBUG4 (("  %d col %d\n", COL_IS_ALIVE (c), c)) ;
+       }
+    }
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+       DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
+       if (COL_IS_DEAD (c))
+       {
+           continue ;
+       }
+       DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
+               Col [c].start, Col [c].length,
+               Col [c].shared1.thickness, Col [c].shared2.score)) ;
+       cp = &A [Col [c].start] ;
+       cp_end = cp + Col [c].length ;
+       while (cp < cp_end)
+       {
+           r = *cp++ ;
+           DEBUG4 (("  %d row %d\n", ROW_IS_ALIVE (r), r)) ;
+       }
+    }
+}
+
+PRIVATE void colamd_get_debug
+(
+    char *method
+)
+{
+    FILE *f ;
+    colamd_debug = 0 ;         /* no debug printing */
+    f = fopen ("debug", "r") ;
+    if (f == (FILE *) NULL)
+    {
+       colamd_debug = 0 ;
+    }
+    else
+    {
+       fscanf (f, "%d", &colamd_debug) ;
+       fclose (f) ;
+    }
+    DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
+       method, colamd_debug)) ;
+}
+
+#endif /* NDEBUG */
diff --git a/extern/colamd/Source/colamd_global.c b/extern/colamd/Source/colamd_global.c
new file mode 100644 (file)
index 0000000..4d1ae22
--- /dev/null
@@ -0,0 +1,24 @@
+/* ========================================================================== */
+/* === colamd_global.c ====================================================== */
+/* ========================================================================== */
+
+/* ----------------------------------------------------------------------------
+ * COLAMD, Copyright (C) 2007, Timothy A. Davis.
+ * See License.txt for the Version 2.1 of the GNU Lesser General Public License
+ * http://www.cise.ufl.edu/research/sparse
+ * -------------------------------------------------------------------------- */
+
+/* Global variables for COLAMD */
+
+#ifndef NPRINT
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+int (*colamd_printf) (const char *, ...) = mexPrintf ;
+#else
+#include <stdio.h>
+int (*colamd_printf) (const char *, ...) = printf ;
+#endif
+#else
+int (*colamd_printf) (const char *, ...) = ((void *) 0) ;
+#endif
+
index c812b3ce6b5d400938e5a534617adb87a48063a1..2e67e70a2e7c0b43606a5b033c32734cf2febdeb 100644 (file)
@@ -15,7 +15,7 @@
 # along with this program; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
-# The Original Code is Copyright (C) 2011 Blender Foundation.
+# The Original Code is Copyright (C) 2011, Blender Foundation
 # All rights reserved.
 #
 # Contributor(s): Blender Foundation,
@@ -26,6 +26,9 @@
 set(INC
        .
        ../Eigen3
+       ./third_party/ssba
+       ./third_party/ldl/Include
+       ../colamd/Include
 )
 
 set(INC_SYS
@@ -37,12 +40,32 @@ set(SRC
        libmv/numeric/numeric.cc
        libmv/numeric/poly.cc
        libmv/numeric/tinyvector.cc
+       libmv/simple_pipeline/reconstruction.cc
+       libmv/simple_pipeline/resect.cc
+       libmv/simple_pipeline/intersect.cc
+       libmv/simple_pipeline/initialize_reconstruction.cc
+       libmv/simple_pipeline/camera_intrinsics.cc
+       libmv/simple_pipeline/pipeline.cc
+       libmv/simple_pipeline/tracks.cc
+       libmv/simple_pipeline/bundle.cc
        libmv/image/convolve.cc
        libmv/image/array_nd.cc
        libmv/tracking/pyramid_region_tracker.cc
        libmv/tracking/trklt_region_tracker.cc
        libmv/tracking/klt_region_tracker.cc
        libmv/tracking/retrack_region_tracker.cc
+       libmv/multiview/projection.cc
+       libmv/multiview/conditioning.cc
+       libmv/multiview/fundamental.cc
+       libmv/multiview/euclidean_resection.cc
+       libmv/multiview/triangulation.cc
+
+       third_party/ssba/Geometry/v3d_metricbundle.cpp
+       third_party/ssba/Math/v3d_optimization.cpp
+       third_party/gflags/gflags.cc
+       third_party/gflags/gflags_reporting.cc
+       third_party/gflags/gflags_completions.cc
+       third_party/ldl/Source/ldl.c
 
        libmv-capi.h
        libmv/logging/logging.h
@@ -51,6 +74,14 @@ set(SRC
        libmv/numeric/poly.h
        libmv/numeric/function_derivative.h
        libmv/numeric/numeric.h
+       libmv/simple_pipeline/resect.h
+       libmv/simple_pipeline/reconstruction.h
+       libmv/simple_pipeline/camera_intrinsics.h
+       libmv/simple_pipeline/tracks.h
+       libmv/simple_pipeline/pipeline.h
+       libmv/simple_pipeline/intersect.h
+       libmv/simple_pipeline/bundle.h
+       libmv/simple_pipeline/initialize_reconstruction.h
        libmv/image/convolve.h
        libmv/image/tuple.h
        libmv/image/array_nd.h
@@ -65,6 +96,97 @@ set(SRC
        libmv/base/vector.h
        libmv/base/scoped_ptr.h
        libmv/base/vector_utils.h
+       libmv/multiview/nviewtriangulation.h
+       libmv/multiview/resection.h
+       libmv/multiview/euclidean_resection.h
+       libmv/multiview/triangulation.h
+       libmv/multiview/projection.h
+       libmv/multiview/fundamental.h
+       libmv/multiview/conditioning.h
+
+       third_party/ssba/Geometry/v3d_metricbundle.h
+       third_party/ssba/Geometry/v3d_cameramatrix.h
+       third_party/ssba/Geometry/v3d_distortion.h
+       third_party/ssba/Math/v3d_linear_utils.h
+       third_party/ssba/Math/v3d_optimization.h
+       third_party/ssba/Math/v3d_mathutilities.h
+       third_party/ssba/Math/v3d_linear.h
+       third_party/gflags/gflags_completions.h
+       third_party/gflags/mutex.h
+       third_party/gflags/config.h
+       third_party/gflags/gflags.h
+       third_party/ldl/Include/ldl.h
+       third_party/msinttypes/stdint.h
+       third_party/msinttypes/inttypes.h
 )
 
+IF(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/logging.cc
+               third_party/glog/src/raw_logging.cc
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/windows/port.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/windows/glog/raw_logging.h
+               third_party/glog/src/windows/glog/vlog_is_on.h
+               third_party/glog/src/windows/glog/logging.h
+               third_party/glog/src/windows/glog/log_severity.h
+               third_party/glog/src/windows/port.h
+               third_party/glog/src/windows/config.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src/windows
+               ./third_party/msinttypes
+       )
+ELSE(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/symbolize.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/signalhandler.cc
+               third_party/glog/src/logging.cc
+               third_party/glog/src/demangle.cc
+               third_party/glog/src/raw_logging.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/config_mac.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/symbolize.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/demangle.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/glog/raw_logging.h
+               third_party/glog/src/glog/vlog_is_on.h
+               third_party/glog/src/glog/logging.h
+               third_party/glog/src/glog/log_severity.h
+               third_party/glog/src/config_linux.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src
+       )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
+
 blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
new file mode 100644 (file)
index 0000000..9065716
--- /dev/null
@@ -0,0 +1,726 @@
+commit df1d54efd23530891851d3573a5126094acea840
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Mon Jul 4 13:12:53 2011 -0700
+
+    Fix include ordering.
+
+commit 67433907db5537a2e32893ef558c63ab336f59c1
+Merge: 0049521 b027af4
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Mon Jul 4 04:01:44 2011 -0700
+
+    Merge Matthias's branch.
+
+commit 0049521756bf03c88061ccc46d0a97397cc77094
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Mon Jul 4 03:18:05 2011 -0700
+
+    Fix build break caused by removing out-of-place definition of P_from_KRt.
+
+commit 40b38d52f71ba61af9d2b00a5077d6346b83d669
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Mon Jul 4 03:07:46 2011 -0700
+
+    Improvements to reconstruction.h documentation.
+
+commit b027af4662007c50a12c08e1991fb9b1124a3a87
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jul 4 10:22:54 2011 +0200
+
+    use P_From_KRt from projection.cc.
+
+commit b082a3e50c79e168e79e51d1571cd2e9b31aa2c2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Jul 3 19:33:30 2011 +0200
+
+    Make unit testing optionnal.
+    Restore user defined camera intrinsincs.
+    Reduce subjective view speed.
+
+commit 144618f9bb247c33e7530118b1ff5aca608573af
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 30 02:33:09 2011 -0700
+
+    Add missing headers.
+
+commit 41b185566506a3583dc7d2aa46b48fa647d30177
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 30 02:32:50 2011 -0700
+
+    Disable projective resection for now.
+
+commit c0f6582f01d3529f757cccd83e7b76ffb1184f1f
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 30 02:31:07 2011 -0700
+
+    Fix a uninitialized memory error in reconstruction.
+    
+    With this change, the elevator sequence now reconstructs with 0.2 pixel average
+    reprojection error. That's over about 2000 markers, 120 frames, and 25 tracks.
+    Reconstruction is now working for real!
+
+commit 3dc34c599eaf69d7903e2213f68196fd32d69439
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 30 01:31:08 2011 -0700
+
+    Split multiview.h/cc up into individual files to keep compile times sane.
+
+commit c3b3296905f7b67ea038058b51efa8cd76e232ba
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 29 22:46:58 2011 -0700
+
+    Add bundling support to simple pipeline. It seems to work pretty well.
+
+commit 4a3ebd309f551abe3197dc573cd7549941d74efd
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 29 10:33:27 2011 -0700
+
+    Fix return type in multiview minimization.
+
+commit 045ff6625a3de3fff98e9f4c153376f2143d2c3d
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:27:33 2011 -0700
+
+    Add hacky hardcoded calls into multiview from qt-tracker.
+
+commit 8c1dec581afbb06e45ed6f15dd72c64b90f52409
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:25:38 2011 -0700
+
+    Add Intersect and Resect implementations, including nonlinear refinement with Levenberg-Marquardt.
+
+commit 63939617aa39a8012154b6f18cf65b671a57880d
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:10:48 2011 -0700
+
+    Add const and non-const accessors to Reconstruction.
+
+commit b95015c8e99d7c9c37c13c3efdc4e6c87cece53d
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:09:56 2011 -0700
+
+    Return false from euclidean resection if it does not work.
+
+commit 437ab722d16c442f27b9c63af3a43468a564a2ef
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:09:15 2011 -0700
+
+    Formatting.
+
+commit c7156a6fcaf7ca8d30d624abeefcd9ddf1087bea
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:04:21 2011 -0700
+
+    More testing fixes.
+
+commit ba9e89674a49aa3b5372dd721dd413d90222a064
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:04:03 2011 -0700
+
+    Reenable testing.
+
+commit 0f9a11ace1294f9d857683779747d367923d48a2
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 28 10:03:36 2011 -0700
+
+    Add a test for camera intrinsics.
+
+commit 37ae9aea4541c9211cd983ce44a875f037136bd7
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Mon Jun 27 02:36:41 2011 -0700
+
+    Get simple reconstruction pipeline is running without BA. Doesn't work well yet.
+
+commit 656f4588f2dbb7672c7233bee5425b34e5ba8aa4
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sun Jun 26 23:06:22 2011 -0700
+
+    Fix PointForTrack() in the Reconstruction object.
+
+commit b27afb3168c23671c130c0f92e24643204034d3e
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sun Jun 26 23:05:39 2011 -0700
+
+    Clarify documenattion in pipelien.h.
+
+commit afd5c5b57999282a7f800c17c05d9020423843b3
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sun Jun 26 23:05:15 2011 -0700
+
+    Add more source files to multiview that got removed.
+
+commit 2916c0f0c29c1e03a11773ac6615a7dbfbc9c058
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sun Jun 26 23:04:24 2011 -0700
+
+    Implement Intersect() and Resect() in multiview.cc.
+
+commit ff2478331a98d0bf2e83b7b03a501049741b1d0e
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sun Jun 26 23:03:45 2011 -0700
+
+    Clarify documentation in multiview.h.
+
+commit f7670aab1b101f68802bc35bc1b64c3d55fa5f3c
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 23 16:18:44 2011 +0200
+
+    fix EnforceFundamentalRank2Constraint
+
+commit a3e29213bdd959502d2fdc077ac479d2b59db0c8
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 22 23:30:54 2011 +0200
+
+    fix CoordinatesForMarkersInImage
+
+commit 9e5f84b6cb063bdca8649b76b4f9769e35823f5d
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 22 20:26:33 2011 +0200
+
+    Remove random data generation, use InsertPoint in Intersect.
+
+commit a41b10fa74f0e7977654a43bb7367704b638bede
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 22 16:24:26 2011 +0200
+
+    hook NViewTriangulate to simple_pipeline/multiview Intersect API.
+    
+    Use libmv::vector instead of std::vector to avoid conflicts.
+    Convert iterator-based loops to counter-based loops as libmv::vector doesn't support iteration.
+
+commit 67b7437b074cb0dfdc26422dd29b9aba1cb906f4
+Merge: 045ca85 c257195
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 22 10:28:48 2011 +0200
+
+    Merge branch 'master' of git://github.com/keir/libmv
+    
+    Conflicts:
+       src/libmv/simple_pipeline/multiview.cc
+
+commit 045ca85dde561c6ec84621ae8f8a67757152dc62
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 21 22:19:33 2011 +0200
+
+    Only reconstruct when we have at least 8 tracks, remove tracks from selections when no markers.
+
+commit 7b593875e6ba089d997ef9a7ff0df255c8883ea4
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 21 21:57:12 2011 +0200
+
+    only lens distort in overlay, fix keyframes creation.
+
+commit 4ff8e9762a4816bf3634578c2c4886e655120698
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 21 21:50:15 2011 +0200
+
+    MacOS support.
+
+commit c2571954d8d88b45b2f05be139fef06f308228ee
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 21 10:35:51 2011 -0700
+
+    Rework multiview.h doxygen comments.
+
+commit fb1c93590a67ba95d550f351c1d297699cdceffb
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 21 09:26:17 2011 -0700
+
+    Remove use od constBits() which is not present in Qt 4.6.
+
+commit 5a1883edb1b5b2b56b31ba929a1a077f53187306
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 21 09:26:00 2011 -0700
+
+    Make multiview.cc compile.
+
+commit 5ca168c45291205b387683ef679dbee18af23e72
+Merge: 9aea3ad 1de8d03
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 21 01:35:20 2011 -0700
+
+    Merge branch 'master' of git://github.com/Matthias-Fauconneau/libmv
+
+commit 9aea3adc56234b059a7ee10a6ff946c3a67ee699
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 21 01:34:40 2011 -0700
+
+    Progress on multiview code in simple pipeline.
+
+commit 1de8d0326cfe2c1b1d1b151b9eef147fca3c72c9
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 20 23:16:46 2011 +0200
+
+    Add back third_party/glog and third_party/gflag to build system as they are needed to compile multiview with logging in debug mode.
+
+commit a51662a259a6c946b5f84c3e0e3b351e9ea4105c
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 20 19:13:40 2011 +0200
+
+    Implement keyframe selection, Fix Tracks::MarkersForTracksInBothImages, Use Reconstruction methods.
+
+commit 2d6cd58ee1cd7c5073980f358c71b2898ad16b4c
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 20 14:15:37 2011 +0200
+
+    Add Simple Pipeline API header and documentation.
+    Make rebuilding much faster by removing unneeded dependencies.
+
+commit 7af3c1af55e42a8091b95ece38bbd1dbefa64013
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 20 12:52:44 2011 +0200
+
+    Add documentation to MultiView and Reconstruction APIs.
+
+commit 308fbc7d87c8d7189c588eb56a563d1f1ff926ba
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Jun 19 20:37:49 2011 +0200
+
+    Update the README.
+
+commit 340b69b2afa4d6c48a019c083bfd0a705bb12165
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Jun 19 20:28:22 2011 +0200
+
+    Change default build options to avoid spurious build failure reports.
+
+commit 2e1c6ef7803bbe8ef53237e2027764e932c404f9
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Jun 18 12:17:59 2011 +0200
+
+    Set maximum focal length to FLT_MAX.
+
+commit a213989750b7f080a2c543203865262a0d40252e
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Jun 18 12:01:52 2011 +0200
+
+    Fix issues caused by style changes.
+
+commit cea54e0207696bb09cadeefbce7bb2a4f1e4c996
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Jun 17 22:46:10 2011 +0200
+
+    Add many whitespaces and newlines.
+
+commit fd01f5139fe720fbe3e8206de27b48519c3de947
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Jun 17 13:05:05 2011 +0200
+
+    Add low order lens distortion for reprojected bundle preview.
+    
+    TODO: Test if the distortion is correct.
+
+commit 8aca7f45513b3cdc2b4b3cf04bd6c11aecf0a756
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 23:02:17 2011 +0200
+
+    Add Solve button and a solve() stub.
+
+commit 60b24a44cebdb7308d19e0b472349eadac42fdde
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 21:41:08 2011 +0200
+
+    Fix first MaxImage() and MaxTrack().
+    Correct transform for Zoom view.
+    Display whole track for visible markers.
+
+commit 3cc45633279ac6fdcdfcae70db03301c69ad609b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 19:58:07 2011 +0200
+
+    Persistent Settings.
+
+commit 8c5b8de3019013cbdbcf019352c49fc3dc1b181b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 19:19:41 2011 +0200
+
+    Add Camera parameters GUI.
+    
+    TODO: persistent parameters.
+    TODO: Feed the data to Multiview API.
+
+commit 7db187d7035bc7f5adee3771125867e9b892d03a
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 18:34:40 2011 +0200
+
+    Smaller bundle display, Display bundles in overlay.
+
+commit 9bf3ccee0f846cdfa5358b367ca35bf68d726df3
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 10:26:12 2011 +0200
+
+    Display 3D Scene overlay on 2D Tracker view.
+
+commit 3e795fa9f5aa7c461d2d65507af5d7b7d4e976ab
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 16 00:26:12 2011 +0200
+
+    Fix tracking (was wrong coordinate transform).
+
+commit f3dc249c6cf417c0bed7455ff4a974d59088d369
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 22:56:56 2011 +0200
+
+    attribute should have been varying.
+
+commit cfe8f83cea71d0fe46159cdb4b750c5888ae2065
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 22:49:53 2011 +0200
+
+    NVidia GLSL compiler is really not strict enough...
+
+commit 13eb0c74ee49cc15827c88fe7f7ae6a0f29e378b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 22:46:20 2011 +0200
+
+    correct GLSL 1.2
+
+commit a8e9cfffac479cd0af0a4e461a9204e4685fd01e
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 22:26:36 2011 +0200
+
+    Remove unused GL abstraction, Downgrade GLSL requirement to 1.20, use GLEW by default even on linux.
+
+commit f9a29280ede36f6a3a894d2eea51dc7f4a1f62e2
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 21:58:35 2011 +0200
+
+    Add GL Zoom Views.
+    
+    This new implementation now display all selected markers.
+
+commit 9e339a46668e4a8d2330598a66ee855e5cd26f9c
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 19:23:21 2011 +0200
+
+    Reimplement 2D Tracker View to use GL.
+    
+    This will allow to easily render the 3D Scene overlay on the 2D Tracker View.
+    Add Tracks::MarkerInImageForTrack.
+    Some renames to improve consistency.
+    Zoom view still need to be readded.
+
+commit 32c9a3010066363f37a275dcbc712d27454e2e87
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 10:11:00 2011 +0200
+
+    Comment non-essential GL calls which don't link properly on some GL implementations.
+
+commit 2260465ac4f3963cc56a7e310b142382dfe5d203
+Merge: 24eacab a45e91d
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 14 20:00:43 2011 -0700
+
+    Merge branch 'master' of git://github.com/Matthias-Fauconneau/libmv
+
+commit 24eacab863638551824534b8777ad5fbcaf688b9
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Tue Jun 14 20:00:32 2011 -0700
+
+    Implement CoordinatesForMarkersInImage in the simple pipeline.
+
+commit a45e91d9285bdb191781d9c4031e925a3e2475c9
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 15 00:34:35 2011 +0200
+
+    Bundle,Camera,Object persistence, Render from Camera.
+    
+    Render from Camera doesn't overlay on 2D View yet.
+    Would be easier to reimplement 2D View using GL.
+
+commit c2e6e58533d24e78036b8a8d6b915458500af58f
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 14 22:39:17 2011 +0200
+
+    Implement Object support.
+    
+    Match code style.
+    Add objects.
+    Display objects.
+    Select objects.
+    Link active object to selected bundles.
+
+commit 26668a24bf63a98ed2519fe4b6bd6dff1760645d
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 14 19:58:18 2011 +0200
+
+    Implement Camera selection.
+    
+    Camera selection bounds is a sphere around camera origin.
+    TODO: we might want an accurate pyramid intersection.
+    Reconstruction::AllPoints() and Reconstruction::AllCameras() now only returns valid objects.
+
+commit da716826247e7afa152bf3598852b3fc013b51c0
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 13 21:17:34 2011 +0200
+
+    Implement bundle selection.
+
+commit 37714c581c585f8efb1212704459f91e26e32b31
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 13 15:01:22 2011 +0200
+
+    Use Reconstruction container.
+    
+    Add Reconstruction::AllCameras() and Recontruction::AllPoints().
+
+commit ab40db86cc9fd3fd9e031e3029f618b68a0a4158
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Mon Jun 13 11:26:33 2011 +0200
+
+    display random cameras
+
+commit 95a150f80325abad21f746cf46f165922673a791
+Merge: cefe6aa 007aa36
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sun Jun 12 10:18:28 2011 +0200
+
+    Merge branch 'master' of git://github.com/keir/libmv
+
+commit 007aa3629ea4f5f74355e896dd29da191b39b03b
+Merge: 2ae39cb daab3ad
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Sat Jun 11 17:43:51 2011 -0700
+
+    Merge pull request #1 from paulinus/master
+    
+    This makes the project compile on the mac.
+
+commit daab3ad96dbf6defe153b97b28b78a3d99a7a092
+Author: Pau Gargallo <pau.gargallo@gmail.com>
+Date:   Sun Jun 12 01:12:30 2011 +0200
+
+    Make it compile on snow leopard.
+    
+    Mostly adding target_link_libraries. Aparently, on the mac, dynamic libs need to be linked against other libs they use.  Also fixed some minor C++ problems, which should not be mac related.
+
+commit cefe6aa584a72355ad42fdfff1bf9a183a2d2eae
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Jun 11 12:28:19 2011 +0200
+
+    Draw dummy 3D points.
+
+commit 7c21196249eecd579dcc1bcb056d36fba0f12bfe
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Sat Jun 11 00:42:34 2011 +0200
+
+    UI fixes, better layouting, add scene view dock widget.
+
+commit 0eebc21db831211738acc938566bbc29d68d45db
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Fri Jun 10 17:31:23 2011 +0200
+
+    Add GL abstraction, Add 3D View, Small cleanups.
+    
+    3D View is not hooked in UI yet.
+    BUG: Image didn't fit to window on startup.
+    TODO: use extern templates instead of not compiling multiview
+
+commit 527e706ed8b7778f3d2e1f03236867c272a70195
+Merge: 2ae39cb 36e9069
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 19:39:15 2011 -0700
+
+    Merge branch 'master' of git://github.com/Matthias-Fauconneau/libmv
+
+commit 5395ef35f452f6456f683d1fdb549500bfd2fe95
+Merge: 36e9069 2ae39cb
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 9 21:26:51 2011 +0200
+
+    Merge branch 'master' of git://github.com/keir/libmv
+
+commit 2ae39cbf78f970f0e732eafeca6548f3b2b9ad1b
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 09:25:02 2011 -0700
+
+    Add forgotten multiview header.
+
+commit 36e9069e2755aee74d70b8f1e56eb075e906ffa1
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 9 14:38:27 2011 +0200
+
+    Fix build (Disabling pipeline.cc since multiview.h is missing).
+
+commit d459d827d49a072622882c7b43ca97d43c13c98e
+Merge: 6fec735 cce784d
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 9 12:30:37 2011 +0200
+
+    Merge branch 'master' of git://github.com/keir/libmv
+
+commit 6fec735ff44447f9a3476a7c82d2f9163e51e536
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 9 12:30:17 2011 +0200
+
+    Cosmetics for Qt Tracker.
+
+commit cce784d47a408d0fec1097ddfac7f4536f692d1b
+Merge: d4b61b7 56f49b5
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 03:18:18 2011 -0700
+
+    Merge Nathan's cleanup branch.
+
+commit d4b61b7d322b7e19abe19f17a2f92cc8af6809fb
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 03:15:46 2011 -0700
+
+    Get simple reconstruction pipeline to build.
+    
+    Removes much of the stuff I originally added such as keyframe estimation; we'll
+    add it back later.
+
+commit aef9ac10a5136d2f34f751618db1316044844d86
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 03:15:29 2011 -0700
+
+    Qt style docs for region_tracker.h.
+
+commit b94a05626c92f48ee0c877808f76e29ce3fd113e
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 03:10:12 2011 -0700
+
+    Qt style formatting for random_sample.h.
+
+commit 97371495b4aae534894f2ec944d64e64176a111e
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 02:36:57 2011 -0700
+
+    Switch tracks to Qt style doxygen comments.
+
+commit e0b619fa42b35f619419fd4d90321db6fd5a703c
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 02:36:19 2011 -0700
+
+    Support Qt style doxygen comments.
+
+commit 0ac0affb94324521c835aded8753aabcc97cb6b1
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 00:51:09 2011 -0700
+
+    Fix doxygen comments on the Tracks class.
+
+commit a59a9a0284ad28266543deda3bfa8a4f4822b33c
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Thu Jun 9 00:50:58 2011 -0700
+
+    Fix comment.
+
+commit a61e0f443d8d5e1c6b7dbcc647a3f28174bc5410
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 22:26:39 2011 -0700
+
+    Switch to the TRKLT in the tracker. Fix a compile issue.
+
+commit 230e7d159f4cd6b067aab5840525b3fa364d7da7
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 22:24:52 2011 -0700
+
+    Add implementation of time-reversible KLT.
+
+commit b4617d8d9758b261442a01e415e76b3ae386fd79
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 20:38:19 2011 -0700
+
+    Fix the "Cancel" button on open in the tracker. Style fixups.
+
+commit 3c58adc840b3d91f367ce5e56bd51c5506197cb1
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Thu Jun 9 01:32:25 2011 +0200
+
+    Improve API, Support marker and track deletion.
+
+commit f026b5a3c4b7b17171cd3b464fdde97dfe7cb729
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 23:25:49 2011 +0200
+
+    Implement persistent tracks (i.e load/save to file)
+
+commit 4bec3680d9a9020daf9dc44967646960de1ae3b3
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 19:43:15 2011 +0200
+
+    Support backwards tracking.
+    Add button to enable automatic tracking of selected markers.
+    Add Oxygen icons to better support platforms without Oxygen theme (i.e Windows).
+    Add Doxygen documentation to public Tracks and Region Tracker API.
+
+commit 56f49b5ce44f32d24f372d5fe188827a35994b05
+Author: Nathan Wiegand <nathanwiegand@gmail.com>
+Date:   Wed Jun 8 10:15:42 2011 -0700
+
+    Fixed more whitespace issues
+
+commit 5b351a1c2a42ace0e84f890fe0a88bed1f5832cd
+Merge: 8667426 e3504fb
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 14:08:06 2011 +0200
+
+    Merge branch 'master' of git://github.com/keir/libmv
+
+commit 8667426a8866c10e59fcd9ae5a454dd594601a0c
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 14:05:41 2011 +0200
+
+    split tracker.cc in two files.
+    
+    - tracker.cc: implement Tracker which handles TrackItems
+    - main.cc: implement UI and seeking
+
+commit c3eef4d1a02c96988f7c4cb9dc6718be26da235b
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 11:17:47 2011 +0200
+
+    fix Google cosmetics, fix seek slider
+
+commit e3504fb4b90ef20360f31e11f87967c49eaf73c0
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 00:53:33 2011 -0700
+
+    Add a way to remove the markers for a track from the tracks object.
+
+commit bcc09c55dd5f3dfd07f60c24bfb932c2973859a5
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 00:04:50 2011 -0700
+
+    Fix various bugs in qt-tracker, and restore style.
+    
+    This fixes the track showing and hiding which was broken in the previous
+    version. This also restores libmv style to the file.
+
+commit 9b3dee7a90419b6995050f87196195b808071a5f
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 00:04:36 2011 -0700
+
+    Formatting in tracks.h.
+
+commit c9bc9ca74cedc1705165ae10106fdbc792e2d31c
+Author: Keir Mierle <mierle@gmail.com>
+Date:   Wed Jun 8 00:04:10 2011 -0700
+
+    Relax constraints when downsampling by 2.
+
+commit 316481f3e42a15143ef52d8f742d85171b4337d5
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Wed Jun 8 00:57:58 2011 +0200
+
+    Better API names, Support track editing (i.e move markers), Usability improvements.
+
+commit bf01ecfa93afe348a79af6dc04a8b0dfe0720257
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 7 21:22:06 2011 +0200
+
+    Optimize for large reconstructions (i.e many tracks) with relatively few visible tracks per frame.
+    
+    Concretely, this means intersecting visible sets instead of indexing an array of Track x Frame.
+
+commit 324ca444a8baa41e5c7e3228564681044116ce92
+Author: Matthias Fauconneau <matthias.fauconneau@gmail.com>
+Date:   Tue Jun 7 20:29:24 2011 +0200
+
+    Implement TrackItem selections and zoom view.
+    
+    Make selections behave correctly (introduce TrackItem which stay selected on frame changes).
+    Add a dock widget which will hold details on the currently selected marker.
+    Add a View to the detail dock which stay zoomed on the current selection.
index 212f73f60ee159e6b835db3568bc91e99cd0237e..03f27ce9b39fb4e56913c1e66ee7c5068a03301c 100644 (file)
@@ -4,14 +4,31 @@ import os
 
 Import('env')
 
-defs = ' -DUSE_FORTRAN_BLAS -DNOGUI'
+defs = 'V3DLIB_ENABLE_SUITESPARSE GOOGLE_GLOG_DLL_DECL='
 cflags = []
 
 src = env.Glob("*.cpp")
-src += env.Glob('libmv/numeric/*.cc')
 src += env.Glob('libmv/image/*.cc')
+src += env.Glob('libmv/multiview/*.cc')
+src += env.Glob('libmv/numeric/*.cc')
+src += env.Glob('libmv/simple_pipeline/*.cc')
 src += env.Glob('libmv/tracking/*.cc')
+src += env.Glob('third_party/gflags/*.cc')
+src += env.Glob('third_party/ldl/Source/*.c')
+src += env.Glob('third_party/ssba/Geometry/*.cpp')
+src += env.Glob('third_party/ssba/Math/*.cpp')
+
+incs = '. ../Eigen3'
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+    incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+
+    src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+    src += ['./third_party/glog/src/windows/port.cc']
+else:
+    src += env.Glob("third_party/glog/src/*.cc")
+    incs += ' ./third_party/glog/src'
 
-incs = '. ../Eigen3 '
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
 
 env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=Split(defs), libtype=['extern', 'player'], priority=[20,137], compileflags=cflags )
index b0ee53bd8771f8fbace15cecc53c6d1e42a091c1..c4e6e8656a6e52cf6842aeb701f8e18b40493195 100755 (executable)
@@ -7,7 +7,15 @@ tmp=`mktemp -d`
 
 git clone $repo $tmp/libmv
 
+git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log --since="1 month ago" > ChangeLog
+
+for p in `cat ./patches/series`; do
+  echo "Applying patch $p..."
+  cat ./patches/$p | patch -d $tmp/libmv -p1
+done
+
 rm -rf libmv
+rm -rf third_party
 
 cat "files.txt" | while f=`line`; do
   mkdir -p `dirname $f`
@@ -16,17 +24,60 @@ done
 
 rm -rf $tmp
 
-sources=`find ./libmv -type f -iname '*.cc' | sed -r 's/^\.\//\t/'`
+chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
+
+sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/'`
 headers=`find ./libmv -type f -iname '*.h' | sed -r 's/^\.\//\t/'`
 
-src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; | sed -r 's/^\.\//\t/' | uniq`
+third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | sed -r 's/^\.\//\t/'`
+third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | sed -r 's/^\.\//\t/'`
+
+third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t/'`
+
+src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort | uniq`
+src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/'  | sort | uniq`
 src=""
-for x in $src_dir; do
-  t="src += env.Glob('`echo $x'/*.cc'`')"
-  if [ -z "$src" ]; then
-    src=$t
+win_src=""
+for x in $src_dir $src_third_dir; do
+  t=""
+
+  if test  `echo "$x" | grep -c glog ` -eq 1; then
+    continue;
+  fi
+
+  if stat $x/*.cpp > /dev/null 2>&1; then
+    t="src += env.Glob('`echo $x'/*.cpp'`')"
+  fi
+
+  if stat $x/*.c > /dev/null 2>&1; then
+    if [ -z "$t" ]; then
+      t="src += env.Glob('`echo $x'/*.c'`')"
+    else
+      t="$t + env.Glob('`echo $x'/*.c'`')"
+    fi
+  fi
+
+  if stat $x/*.cc > /dev/null 2>&1; then
+    if [ -z "$t" ]; then
+      t="src += env.Glob('`echo $x'/*.cc'`')"
+    else
+      t="$t + env.Glob('`echo $x'/*.cc'`')"
+    fi
+  fi
+
+  if test `echo $x | grep -c windows ` -eq 0; then
+    if [ -z "$src" ]; then
+      src=$t
+    else
+      src=`echo "$src\n$t"`
+    fi
   else
-    src=`echo "$src\n$t"`
+    if [ -z "$win_src" ]; then
+      win_src=`echo "    $t"`
+    else
+      win_src=`echo "$win_src\n    $t"`
+    fi
   fi
 done
 
@@ -59,6 +110,9 @@ cat > CMakeLists.txt << EOF
 set(INC
        .
        ../Eigen3
+       ./third_party/ssba
+       ./third_party/ldl/Include
+       ../colamd/Include
 )
 
 set(INC_SYS
@@ -69,53 +123,60 @@ set(SRC
        libmv-capi.cpp
 ${sources}
 
+${third_sources}
+
        libmv-capi.h
 ${headers}
-)
 
-blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
-EOF
+${third_headers}
+)
 
-cat > libmv/logging/logging.h << EOF
-// Copyright (c) 2007, 2008, 2009 libmv authors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-#ifndef LIBMV_LOGGING_LOGGING_H
-#define LIBMV_LOGGING_LOGGING_H
-
-#include <iostream>
-
-class DummyLogger {
-public:
-       DummyLogger operator << (const ::std::wstring& wstr) { return *this; }
-       DummyLogger operator << (const char *pchar) { return *this; }
-       DummyLogger operator << (int a) { return *this; }
-};
-
-#define LG (DummyLogger())
-#define V0 (DummyLogger())
-#define V1 (DummyLogger())
-#define V2 (DummyLogger())
-
-#endif  // LIBMV_LOGGING_LOGGING_H
+IF(WIN32)
+       list(APPEND SRC
+               third_party/glog/src/logging.cc
+               third_party/glog/src/raw_logging.cc
+               third_party/glog/src/utilities.cc
+               third_party/glog/src/vlog_is_on.cc
+               third_party/glog/src/windows/port.cc
+
+               third_party/glog/src/utilities.h
+               third_party/glog/src/stacktrace_generic-inl.h
+               third_party/glog/src/stacktrace.h
+               third_party/glog/src/stacktrace_x86_64-inl.h
+               third_party/glog/src/base/googleinit.h
+               third_party/glog/src/base/mutex.h
+               third_party/glog/src/base/commandlineflags.h
+               third_party/glog/src/stacktrace_powerpc-inl.h
+               third_party/glog/src/stacktrace_x86-inl.h
+               third_party/glog/src/config.h
+               third_party/glog/src/stacktrace_libunwind-inl.h
+               third_party/glog/src/windows/glog/raw_logging.h
+               third_party/glog/src/windows/glog/vlog_is_on.h
+               third_party/glog/src/windows/glog/logging.h
+               third_party/glog/src/windows/glog/log_severity.h
+               third_party/glog/src/windows/port.h
+               third_party/glog/src/windows/config.h
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src/windows
+               ./third_party/msinttypes
+       )
+ELSE(WIN32)
+       list(APPEND SRC
+${third_glog_sources}
+
+${third_glog_headers}
+       )
+
+       list(APPEND INC
+               ./third_party/glog/src
+       )
+ENDIF(WIN32)
+
+add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
 
+blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
 EOF
 
 cat > SConscript << EOF
@@ -125,13 +186,24 @@ import os
 
 Import('env')
 
-defs = ' -DUSE_FORTRAN_BLAS -DNOGUI'
+defs = 'V3DLIB_ENABLE_SUITESPARSE GOOGLE_GLOG_DLL_DECL='
 cflags = []
 
 src = env.Glob("*.cpp")
 $src
 
-incs = '. ../Eigen3 '
+incs = '. ../Eigen3'
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+    incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
+${win_src}
+    src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
+    src += ['./third_party/glog/src/windows/port.cc']
+else:
+    src += env.Glob("third_party/glog/src/*.cc")
+    incs += ' ./third_party/glog/src'
+
+incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
 
 env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=Split(defs), libtype=['extern', 'player'], priority=[20,137], compileflags=cflags )
 EOF
index f5a0c5f604dbca2c8a95445f63f28a3427f3d53d..e0177acc5119376d3323401d6f3dc21180770a2e 100644 (file)
@@ -7,6 +7,22 @@ libmv/numeric/function_derivative.h
 libmv/numeric/poly.cc
 libmv/numeric/tinyvector.cc
 libmv/numeric/numeric.h
+libmv/simple_pipeline/reconstruction.cc
+libmv/simple_pipeline/resect.h
+libmv/simple_pipeline/resect.cc
+libmv/simple_pipeline/reconstruction.h
+libmv/simple_pipeline/camera_intrinsics.h
+libmv/simple_pipeline/intersect.cc
+libmv/simple_pipeline/initialize_reconstruction.cc
+libmv/simple_pipeline/camera_intrinsics.cc
+libmv/simple_pipeline/pipeline.cc
+libmv/simple_pipeline/tracks.h
+libmv/simple_pipeline/pipeline.h
+libmv/simple_pipeline/tracks.cc
+libmv/simple_pipeline/bundle.cc
+libmv/simple_pipeline/intersect.h
+libmv/simple_pipeline/bundle.h
+libmv/simple_pipeline/initialize_reconstruction.h
 libmv/image/convolve.h
 libmv/image/tuple.h
 libmv/image/array_nd.h
@@ -27,3 +43,85 @@ libmv/base/id_generator.h
 libmv/base/vector.h
 libmv/base/scoped_ptr.h
 libmv/base/vector_utils.h
+libmv/multiview/projection.cc
+libmv/multiview/conditioning.cc
+libmv/multiview/nviewtriangulation.h
+libmv/multiview/resection.h
+libmv/multiview/fundamental.cc
+libmv/multiview/euclidean_resection.cc
+libmv/multiview/euclidean_resection.h
+libmv/multiview/triangulation.h
+libmv/multiview/projection.h
+libmv/multiview/triangulation.cc
+libmv/multiview/fundamental.h
+libmv/multiview/conditioning.h
+third_party/ssba/README.TXT
+third_party/ssba/COPYING.TXT
+third_party/ssba/Geometry/v3d_metricbundle.h
+third_party/ssba/Geometry/v3d_metricbundle.cpp
+third_party/ssba/Geometry/v3d_cameramatrix.h
+third_party/ssba/Geometry/v3d_distortion.h
+third_party/ssba/README.libmv
+third_party/ssba/Math/v3d_linear_utils.h
+third_party/ssba/Math/v3d_optimization.h
+third_party/ssba/Math/v3d_mathutilities.h
+third_party/ssba/Math/v3d_linear.h
+third_party/ssba/Math/v3d_optimization.cpp
+third_party/gflags/gflags_completions.h
+third_party/gflags/mutex.h
+third_party/gflags/gflags.cc
+third_party/gflags/gflags_reporting.cc
+third_party/gflags/README.libmv
+third_party/gflags/config.h
+third_party/gflags/gflags_completions.cc
+third_party/gflags/gflags.h
+third_party/ldl/Include/ldl.h
+third_party/ldl/CMakeLists.txt
+third_party/ldl/README.libmv
+third_party/ldl/Doc/ChangeLog
+third_party/ldl/Doc/lesser.txt
+third_party/ldl/README.txt
+third_party/ldl/Source/ldl.c
+third_party/glog/ChangeLog
+third_party/glog/COPYING
+third_party/glog/src/utilities.cc
+third_party/glog/src/utilities.h
+third_party/glog/src/symbolize.cc
+third_party/glog/src/stacktrace_generic-inl.h
+third_party/glog/src/config_mac.h
+third_party/glog/src/vlog_is_on.cc
+third_party/glog/src/signalhandler.cc
+third_party/glog/src/stacktrace.h
+third_party/glog/src/stacktrace_x86_64-inl.h
+third_party/glog/src/symbolize.h
+third_party/glog/src/base/googleinit.h
+third_party/glog/src/base/mutex.h
+third_party/glog/src/base/commandlineflags.h
+third_party/glog/src/windows/preprocess.sh
+third_party/glog/src/windows/port.h
+third_party/glog/src/windows/config.h
+third_party/glog/src/windows/glog/raw_logging.h
+third_party/glog/src/windows/glog/vlog_is_on.h
+third_party/glog/src/windows/glog/logging.h
+third_party/glog/src/windows/glog/log_severity.h
+third_party/glog/src/windows/port.cc
+third_party/glog/src/logging.cc
+third_party/glog/src/stacktrace_powerpc-inl.h
+third_party/glog/src/stacktrace_x86-inl.h
+third_party/glog/src/demangle.cc
+third_party/glog/src/config.h
+third_party/glog/src/demangle.h
+third_party/glog/src/stacktrace_libunwind-inl.h
+third_party/glog/src/glog/raw_logging.h
+third_party/glog/src/glog/vlog_is_on.h
+third_party/glog/src/glog/logging.h
+third_party/glog/src/glog/log_severity.h
+third_party/glog/src/raw_logging.cc
+third_party/glog/src/config_linux.h
+third_party/glog/NEWS
+third_party/glog/README
+third_party/glog/README.libmv
+third_party/glog/AUTHORS
+third_party/msinttypes/stdint.h
+third_party/msinttypes/inttypes.h
+third_party/msinttypes/README.libmv
index fb0aa9fa223d9ece9f30298f98afc9c032fa198c..c0393ee99a2b2087f5fd64b7708d51c4cb689abd 100644 (file)
 
 #include "libmv-capi.h"
 
+#include "glog/logging.h"
+#include "Math/v3d_optimization.h"
+
 #include "libmv/tracking/klt_region_tracker.h"
 #include "libmv/tracking/trklt_region_tracker.h"
 #include "libmv/tracking/pyramid_region_tracker.h"
 #include "libmv/tracking/retrack_region_tracker.h"
 
+#include "libmv/simple_pipeline/tracks.h"
+#include "libmv/simple_pipeline/initialize_reconstruction.h"
+#include "libmv/simple_pipeline/bundle.h"
+#include "libmv/simple_pipeline/pipeline.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+
 #include <stdlib.h>
 
 #ifdef DUMP_FAILURE
 #  include <png.h>
 #endif
 
+#ifdef _MSC_VER
+#  define snprintf _snprintf
+#endif
+
 #define DEFAULT_WINDOW_HALFSIZE        5
 
-typedef struct ConfiguredRegionTracker {
+typedef struct libmv_RegionTracker {
        libmv::TrkltRegionTracker *trklt_region_tracker;
        libmv::PyramidRegionTracker *pyramid_region_tracker;
        libmv::RegionTracker *region_tracker;
-} ConfiguredRegionTracker;
+} libmv_RegionTracker;
+
+/* ************ Logging ************ */
+
+void libmv_initLogging(const char *argv0)
+{
+       google::InitGoogleLogging(argv0);
+       google::SetCommandLineOption("logtostderr", "0");
+       google::SetCommandLineOption("v", "0");
+       google::SetCommandLineOption("stderrthreshold", "7");
+       V3D::optimizerVerbosenessLevel = 0;
+}
+
+void libmv_startDebugLogging(void)
+{
+       google::SetCommandLineOption("logtostderr", "1");
+       google::SetCommandLineOption("v", "0");
+       google::SetCommandLineOption("stderrthreshold", "2");
+       V3D::optimizerVerbosenessLevel = 1;
+}
+
+void libmv_setLoggingVerbosity(int verbosity)
+{
+       char val[10];
+       snprintf(val, sizeof(val), "%d", verbosity);
+
+       google::SetCommandLineOption("v", val);
+       V3D::optimizerVerbosenessLevel = verbosity;
+}
 
-libmv_regionTrackerHandle libmv_regionTrackerNew(int max_iterations, int pyramid_level, double tolerance)
+/* ************ RegionTracker ************ */
+
+libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level, double tolerance)
 {
        libmv::RegionTracker *region_tracker;
        libmv::TrkltRegionTracker *trklt_region_tracker = new libmv::TrkltRegionTracker;
@@ -64,12 +107,12 @@ libmv_regionTrackerHandle libmv_regionTrackerNew(int max_iterations, int pyramid
 
        region_tracker = new libmv::RetrackRegionTracker(pyramid_region_tracker, tolerance);
 
-       ConfiguredRegionTracker *configured_region_tracker = new ConfiguredRegionTracker;
+       libmv_RegionTracker *configured_region_tracker = new libmv_RegionTracker;
        configured_region_tracker->trklt_region_tracker = trklt_region_tracker;
        configured_region_tracker->pyramid_region_tracker = pyramid_region_tracker;
        configured_region_tracker->region_tracker = region_tracker;
 
-       return (libmv_regionTrackerHandle)configured_region_tracker;
+       return configured_region_tracker;
 }
 
 static void floatBufToImage(const float *buf, int width, int height, libmv::FloatImage *image)
@@ -178,18 +221,16 @@ static void saveImage(libmv::FloatImage image, int x0, int y0)
 }
 #endif
 
-int libmv_regionTrackerTrack(libmv_regionTrackerHandle tracker, const float *ima1, const float *ima2,
+int libmv_regionTrackerTrack(libmv_RegionTracker *tracker, const float *ima1, const float *ima2,
                         int width, int height, int half_window_size,
                         double x1, double y1, double *x2, double *y2)
 {
-       ConfiguredRegionTracker *configured_region_tracker;
        libmv::RegionTracker *region_tracker;
        libmv::TrkltRegionTracker *trklt_region_tracker;
        libmv::FloatImage old_patch, new_patch;
 
-       configured_region_tracker = (ConfiguredRegionTracker *)tracker;
-       trklt_region_tracker = configured_region_tracker->trklt_region_tracker;
-       region_tracker = configured_region_tracker->region_tracker;
+       trklt_region_tracker = tracker->trklt_region_tracker;
+       region_tracker = tracker->region_tracker;
 
        trklt_region_tracker->half_window_size = half_window_size;
 
@@ -213,12 +254,117 @@ int libmv_regionTrackerTrack(libmv_regionTrackerHandle tracker, const float *ima
 #endif
 }
 
-void libmv_regionTrackerDestroy(libmv_regionTrackerHandle tracker)
+void libmv_regionTrackerDestroy(libmv_RegionTracker *tracker)
+{
+       delete tracker->region_tracker;
+       delete tracker;
+}
+
+/* ************ Tracks ************ */
+
+libmv_Tracks *libmv_tracksNew(void)
+{
+       libmv::Tracks *tracks = new libmv::Tracks();
+
+       return (libmv_Tracks *)tracks;
+}
+
+void libmv_tracksInsert(struct libmv_Tracks *tracks, int image, int track, double x, double y)
+{
+       ((libmv::Tracks*)tracks)->Insert(image, track, x, y);
+}
+
+void libmv_tracksDestroy(libmv_Tracks *tracks)
+{
+       delete (libmv::Tracks*)tracks;
+}
+
+/* ************ Reconstruction solver ************ */
+
+struct libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
+                       double focal_length, double principal_x, double principal_y, double k1, double k2, double k3)
+{
+       /* Invert the camera intrinsics. */
+       libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
+       libmv::CameraIntrinsics intrinsics;
+       libmv::Reconstruction *reconstruction = new libmv::Reconstruction();
+
+       intrinsics.SetFocalLength(focal_length);
+       intrinsics.set_principal_point(principal_x, principal_y);
+       intrinsics.set_radial_distortion(k1, k2, k3);
+
+       if(focal_length) {
+               /* do a lens undistortion if focal length is non-zero only */
+               for (int i = 0; i < markers.size(); ++i) {
+                       intrinsics.InvertIntrinsics(markers[i].x,
+                               markers[i].y,
+                               &(markers[i].x),
+                               &(markers[i].y));
+               }
+       }
+
+       libmv::Tracks normalized_tracks(markers);
+
+       libmv::vector<libmv::Marker> keyframe_markers =
+               normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+
+       libmv::ReconstructTwoFrames(keyframe_markers, reconstruction);
+       libmv::Bundle(normalized_tracks, reconstruction);
+       libmv::CompleteReconstruction(normalized_tracks, reconstruction);
+       libmv::ReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, intrinsics);
+
+       return (libmv_Reconstruction *)reconstruction;
+}
+
+int libmv_reporojectionPointForTrack(libmv_Reconstruction *reconstruction, int track, double pos[3])
+{
+       libmv::Point *point = ((libmv::Reconstruction *)reconstruction)->PointForTrack(track);
+
+       if(point) {
+               pos[0] = point->X[0];
+               pos[1] = point->X[2];
+               pos[2] = point->X[1];
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int libmv_reporojectionCameraForImage(libmv_Reconstruction *reconstruction, int image, float mat[4][4])
 {
-       ConfiguredRegionTracker *configured_region_tracker;
+       libmv::Camera *camera = ((libmv::Reconstruction *)reconstruction)->CameraForImage(image);
+
+       if(camera) {
+               for (int j = 0; j < 3; ++j) {
+                       for (int k = 0; k < 3; ++k) {
+                               int l = k;
+
+                               if (k == 1) l = 2;
+                               else if (k == 2) l = 1;
+
+                               if (j == 2) mat[j][l] = -camera->R(j,k);
+                               else mat[j][l] = camera->R(j,k);
+                       }
+                       mat[j][3]= 0.0;
+               }
+
+               libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
 
-       configured_region_tracker = (ConfiguredRegionTracker *)tracker;
+               mat[3][0] = optical_center(0);
+               mat[3][1] = optical_center(2);
+               mat[3][2] = optical_center(1);
 
-       delete configured_region_tracker->region_tracker;
-       delete configured_region_tracker;
+               mat[3][3]= 1.0;
+
+               return 1;
+       }
+
+       return 0;
 }
+
+void libmv_destroyReconstruction(libmv_Reconstruction *reconstruction)
+{
+       delete (libmv::Reconstruction *)reconstruction;
+}
+
index 3016aae258a48f1a6499ed43c204a79f74ed7e49..73bd705813d6093d84b089c00f5c87261bd07922 100644 (file)
 extern "C" {
 #endif
 
-typedef void *libmv_regionTrackerHandle;
+struct libmv_RegionTracker;
+struct libmv_Tracks;
+struct libmv_Reconstruction;
 
-/* Regiontracker */
-libmv_regionTrackerHandle libmv_regionTrackerNew(int max_iterations, int pyramid_level, double tolerance);
-int libmv_regionTrackerTrack(libmv_regionTrackerHandle tracker, const float *ima1, const float *ima2,
+/* Logging */
+void libmv_initLogging(const char *argv0);
+void libmv_startDebugLogging(void);
+void libmv_setLoggingVerbosity(int verbosity);
+
+/* RegionTracker */
+struct libmv_RegionTracker *libmv_regionTrackerNew(int max_iterations, int pyramid_level, double tolerance);
+int libmv_regionTrackerTrack(struct libmv_RegionTracker *tracker, const float *ima1, const float *ima2,
                        int width, int height, int half_window_size,
                        double  x1, double  y1, double *x2, double *y2);
-void libmv_regionTrackerDestroy(libmv_regionTrackerHandle tracker);
+void libmv_regionTrackerDestroy(struct libmv_RegionTracker *tracker);
+
+/* Tracks */
+struct libmv_Tracks *libmv_tracksNew(void);
+void libmv_tracksInsert(struct libmv_Tracks *tracks, int image, int track, double x, double y);
+void libmv_tracksDestroy(struct libmv_Tracks *tracks);
+
+/* Reconstruction solver */
+struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
+                       double focal_length, double principal_x, double principal_y, double k1, double k2, double k3);
+int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *reconstruction, int track, double pos[3]);
+int libmv_reporojectionCameraForImage(struct libmv_Reconstruction *reconstruction, int image, float mat[4][4]);
+void libmv_destroyReconstruction(struct libmv_Reconstruction *reconstruction);
 
 #ifdef __cplusplus
 }
index 740df4686f119d477947f9a2846969d9843b1443..0fbd6b0f08feb8c8041d96c036d5fb4df8d6070b 100644 (file)
@@ -35,6 +35,10 @@ namespace libmv {
 // A simple container class, which guarantees 16 byte alignment needed for most
 // vectorization. Don't use this container for classes that cannot be copied
 // via memcpy.
+// FIXME: this class has some issues:
+// - doesn't support iterators.
+// - impede compatibility with code using STL.
+// - the STL already provide support for custom allocators
 template <typename T,
           typename Allocator = Eigen::aligned_allocator<T> >
 class vector {
@@ -68,6 +72,7 @@ class vector {
     std::swap(data_, other.data_);
   }
 
+        T *data()            const { return data_;            }
   int      size()            const { return size_;            }
   int      capacity()        const { return capacity_;        }
   const T& back()            const { return data_[size_ - 1]; }
index 1af6d71a80ef6cf095d087f0652c5969e3ac4de5..d158b0e0397c9058770d5a6ec7ec201169d1d8ae 100644 (file)
@@ -18,8 +18,8 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 
-#ifndef LIBMV_IMAGE_IMAGE_IMAGE_H
-#define LIBMV_IMAGE_IMAGE_IMAGE_H
+#ifndef LIBMV_IMAGE_IMAGE_H
+#define LIBMV_IMAGE_IMAGE_H
 
 #include <cmath>
 
index f65d872b1193d189405cd77384805707035e562e..af86c4baa42b74152f8f03193b6c3364f6759178 100644 (file)
 #ifndef LIBMV_LOGGING_LOGGING_H
 #define LIBMV_LOGGING_LOGGING_H
 
-#include <iostream>
+#include "glog/logging.h"
 
-class DummyLogger {
-public:
-       DummyLogger operator << (const ::std::wstring& wstr) { return *this; }
-       DummyLogger operator << (const char *pchar) { return *this; }
-       DummyLogger operator << (int a) { return *this; }
-};
-
-#define LG (DummyLogger())
-#define V0 (DummyLogger())
-#define V1 (DummyLogger())
-#define V2 (DummyLogger())
+#define LG LOG(INFO)
+#define V0 LOG(INFO)
+#define V1 LOG(INFO)
+#define V2 LOG(INFO)
 
 #endif  // LIBMV_LOGGING_LOGGING_H
-
diff --git a/extern/libmv/libmv/multiview/conditioning.cc b/extern/libmv/libmv/multiview/conditioning.cc
new file mode 100644 (file)
index 0000000..20e3a88
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright (c) 2010 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "libmv/multiview/conditioning.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+// HZ 4.4.4 pag.109: Point conditioning (non isotropic)
+void PreconditionerFromPoints(const Mat &points, Mat3 *T) {
+  Vec mean, variance;
+  MeanAndVarianceAlongRows(points, &mean, &variance);
+
+  double xfactor = sqrt(2.0 / variance(0));
+  double yfactor = sqrt(2.0 / variance(1));
+
+  // If variance is equal to 0.0 set scaling factor to identity.
+  // -> Else it will provide nan value (because division by 0).
+  if (variance(0) < 1e-8)
+    xfactor = mean(0) = 1.0;
+  if (variance(1) < 1e-8)
+    yfactor = mean(1) = 1.0;
+
+  *T << xfactor, 0,       -xfactor * mean(0),
+        0,       yfactor, -yfactor * mean(1),
+        0,       0,        1;
+}
+// HZ 4.4.4 pag.107: Point conditioning (isotropic)
+void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) {
+  Vec mean, variance;
+  MeanAndVarianceAlongRows(points, &mean, &variance);
+
+  double var_norm = variance.norm();
+  double factor = sqrt(2.0 / var_norm);
+
+  // If variance is equal to 0.0 set scaling factor to identity.
+  // -> Else it will provide nan value (because division by 0).
+  if (var_norm < 1e-8) {
+    factor = 1.0;
+    mean.setOnes();
+  }
+
+  *T << factor, 0,       -factor * mean(0),
+        0,       factor, -factor * mean(1),
+        0,       0,        1;
+}
+
+void ApplyTransformationToPoints(const Mat &points,
+                                 const Mat3 &T,
+                                 Mat *transformed_points) {
+  int n = points.cols();
+  transformed_points->resize(2,n);
+  Mat3X p(3, n);
+  EuclideanToHomogeneous(points, &p);
+  p = T * p;
+  HomogeneousToEuclidean(p, transformed_points);
+}
+
+void NormalizePoints(const Mat &points,
+                     Mat *normalized_points,
+                     Mat3 *T) {
+  PreconditionerFromPoints(points, T);
+  ApplyTransformationToPoints(points, *T, normalized_points);
+}
+
+void NormalizeIsotropicPoints(const Mat &points,
+                              Mat *normalized_points,
+                              Mat3 *T) {
+  IsotropicPreconditionerFromPoints(points, T);
+  ApplyTransformationToPoints(points, *T, normalized_points);
+}
+
+// Denormalize the results. See HZ page 109.
+void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H)  {
+  *H = T2.transpose() * (*H) * T1;
+}
+
+void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H)  {
+  *H = T2.inverse() * (*H) * T1;
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/conditioning.h b/extern/libmv/libmv/multiview/conditioning.h
new file mode 100644 (file)
index 0000000..181d748
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBMV_MULTIVIEW_CONDITIONNING_H_
+#define LIBMV_MULTIVIEW_CONDITIONNING_H_
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+// Point conditioning (non isotropic)
+void PreconditionerFromPoints(const Mat &points, Mat3 *T);
+// Point conditioning (isotropic)
+void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T);
+
+void ApplyTransformationToPoints(const Mat &points,
+                                 const Mat3 &T,
+                                 Mat *transformed_points);
+
+void NormalizePoints(const Mat &points,
+                     Mat *normalized_points,
+                     Mat3 *T);
+
+void NormalizeIsotropicPoints(const Mat &points,
+                              Mat *normalized_points,
+                              Mat3 *T);
+
+/// Use inverse for unnormalize
+struct UnnormalizerI {
+  // Denormalize the results. See HZ page 109.
+  static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+};
+
+/// Use transpose for unnormalize
+struct UnnormalizerT {
+  // Denormalize the results. See HZ page 109.
+  static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H);
+};
+
+} //namespace libmv
+
+
+#endif // LIBMV_MULTIVIEW_CONDITIONNING_H_
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc
new file mode 100644 (file)
index 0000000..6d918a1
--- /dev/null
@@ -0,0 +1,661 @@
+// Copyright (c) 2009 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include <cmath>
+#include <limits>
+
+#include <Eigen/SVD>
+#include <Eigen/Geometry>
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/euclidean_resection.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+namespace euclidean_resection {
+
+bool EuclideanResection(const Mat2X &x_camera, 
+                        const Mat3X &X_world,
+                        Mat3 *R, Vec3 *t,
+                        ResectionMethod method) {
+  switch (method) {
+    case RESECTION_ANSAR_DANIILIDIS:
+      EuclideanResectionAnsarDaniilidis(x_camera, X_world, R, t);
+      break;
+    case RESECTION_EPNP:
+      return EuclideanResectionEPnP(x_camera, X_world, R, t);      
+      break;
+    default:
+      LOG(FATAL) << "Unknown resection method.";
+  }
+  return false;
+}
+
+bool EuclideanResection(const Mat &x_image, 
+                        const Mat3X &X_world,
+                        const Mat3 &K,
+                        Mat3 *R, Vec3 *t,
+                        ResectionMethod method) {
+  CHECK(x_image.rows() == 2 || x_image.rows() == 3)
+    << "Invalid size for x_image: "
+    << x_image.rows() << "x" << x_image.cols();
+
+  Mat2X x_camera;
+  if (x_image.rows() == 2) {
+    EuclideanToNormalizedCamera(x_image, K, &x_camera);
+  } else if (x_image.rows() == 3) {
+    HomogeneousToNormalizedCamera(x_image, K, &x_camera);
+  }
+  return EuclideanResection(x_camera, X_world, R, t, method);
+}
+
+void AbsoluteOrientation(const Mat3X &X,
+                         const Mat3X &Xp,
+                         Mat3 *R,
+                         Vec3 *t) {
+  int num_points = X.cols();
+  Vec3 C  = X.rowwise().sum() / num_points;   // Centroid of X.
+  Vec3 Cp = Xp.rowwise().sum() / num_points;  // Centroid of Xp.
+
+  // Normalize the two point sets.
+  Mat3X Xn(3, num_points), Xpn(3, num_points);
+  for( int i = 0; i < num_points; ++i ){
+    Xn.col(i)  = X.col(i) - C;
+    Xpn.col(i) = Xp.col(i) - Cp;
+  }
+  
+  // Construct the N matrix (pg. 635).
+  double Sxx = Xn.row(0).dot(Xpn.row(0));
+  double Syy = Xn.row(1).dot(Xpn.row(1));
+  double Szz = Xn.row(2).dot(Xpn.row(2));
+  double Sxy = Xn.row(0).dot(Xpn.row(1));
+  double Syx = Xn.row(1).dot(Xpn.row(0));
+  double Sxz = Xn.row(0).dot(Xpn.row(2));
+  double Szx = Xn.row(2).dot(Xpn.row(0));
+  double Syz = Xn.row(1).dot(Xpn.row(2));
+  double Szy = Xn.row(2).dot(Xpn.row(1));
+
+  Mat4 N;
+  N << Sxx + Syy + Szz, Syz - Szy,        Szx - Sxz,        Sxy - Syx,
+       Syz - Szy,       Sxx - Syy - Szz,  Sxy + Syx,        Szx + Sxz,
+       Szx - Sxz,       Sxy + Syx,       -Sxx + Syy - Szz,  Syz + Szy,
+       Sxy - Syx,       Szx + Sxz,        Syz + Szy,       -Sxx - Syy + Szz;
+           
+  // Find the unit quaternion q that maximizes qNq. It is the eigenvector
+  // corresponding to the lagest eigenvalue.
+  Vec4 q = N.jacobiSvd(Eigen::ComputeFullU).matrixU().col(0);
+
+  // Retrieve the 3x3 rotation matrix.
+  Vec4 qq = q.array() * q.array();
+  double q0q1 = q(0) * q(1);
+  double q0q2 = q(0) * q(2);
+  double q0q3 = q(0) * q(3);
+  double q1q2 = q(1) * q(2);
+  double q1q3 = q(1) * q(3);
+  double q2q3 = q(2) * q(3);
+
+  (*R) << qq(0) + qq(1) - qq(2) - qq(3),
+          2 * (q1q2 - q0q3),
+          2 * (q1q3 + q0q2),
+          2 * (q1q2+ q0q3),
+          qq(0) - qq(1) + qq(2) - qq(3),
+          2 * (q2q3 - q0q1),
+          2 * (q1q3 - q0q2),
+          2 * (q2q3 + q0q1),
+          qq(0) - qq(1) - qq(2) + qq(3);
+
+  // Fix the handedness of the R matrix.
+  if (R->determinant() < 0) {
+    R->row(2) = -R->row(2);
+  }
+  // Compute the final translation.
+  *t = Cp - *R * C;
+}
+
+// Convert i and j indices of the original variables into their quadratic
+// permutation single index. It follows that t_ij = t_ji.
+static int IJToPointIndex(int i, int j, int num_points) {
+  // Always make sure that j is bigger than i. This handles t_ij = t_ji.
+  if (j < i) {
+    std::swap(i, j);
+  }
+  int idx;
+  int num_permutation_rows = num_points * (num_points - 1) / 2;
+
+  // All t_ii's are located at the end of the t vector after all t_ij's.
+  if (j == i) {
+    idx = num_permutation_rows + i;
+  } else {
+    int offset = (num_points - i - 1) * (num_points - i) / 2;
+    idx = (num_permutation_rows - offset + j - i - 1);
+  }
+  return idx;
+};
+
+// Convert i and j indexes of the solution for lambda to their linear indexes.
+static int IJToIndex(int i, int j, int num_lambda) {
+  if (j < i) {
+    std::swap(i, j);
+  }
+  int A = num_lambda * (num_lambda + 1) / 2;
+  int B = num_lambda - i;
+  int C = B * (B + 1) / 2;
+  int idx = A - C + j - i;
+  return idx;
+};
+
+static int Sign(double value) {
+  return (value < 0) ? -1 : 1;
+};
+
+// Organizes a square matrix into a single row constraint on the elements of
+// Lambda to create the constraints in equation (5) in "Linear Pose Estimation
+// from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no.
+// 5.
+static Vec MatrixToConstraint(const Mat &A,
+                              int num_k_columns,
+                              int num_lambda) {
+  Vec C(num_k_columns);
+  C.setZero();
+  int idx = 0;
+  for (int i = 0; i < num_lambda; ++i) {
+    for( int j = i; j < num_lambda; ++j) {
+      C(idx) = A(i, j);
+      if (i != j){
+        C(idx) += A(j, i);
+      }
+      ++ idx;
+    }
+  }
+  return C;
+}
+
+// Normalizes the columns of vectors.
+static void NormalizeColumnVectors(Mat3X *vectors) {
+  int num_columns = vectors->cols();
+  for (int i = 0; i < num_columns; ++i){
+    vectors->col(i).normalize();
+  }
+}
+
+void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, 
+                                       const Mat3X &X_world,               
+                                       Mat3 *R, 
+                                       Vec3 *t) {
+  CHECK(x_camera.cols() == X_world.cols());
+  CHECK(x_camera.cols() > 3);
+
+  int num_points = x_camera.cols();
+
+  // Copy the normalized camera coords into 3 vectors and normalize them so
+  // that they are unit vectors from the camera center.
+  Mat3X x_camera_unit(3, num_points);
+  x_camera_unit.block(0, 0, 2, num_points) = x_camera;
+  x_camera_unit.row(2).setOnes();
+  NormalizeColumnVectors(&x_camera_unit);
+  
+  int num_m_rows = num_points * (num_points - 1) / 2;
+  int num_tt_variables = num_points * (num_points + 1) / 2;
+  int num_m_columns = num_tt_variables + 1;
+  Mat M(num_m_columns, num_m_columns);
+  M.setZero();
+  Matu ij_index(num_tt_variables, 2);
+
+  // Create the constraint equations for the t_ij variables (7) and arrange
+  // them into the M matrix (8). Also store the initial (i, j) indices.
+  int row=0;
+  for (int i = 0; i < num_points; ++i) {
+    for (int j = i+1; j < num_points; ++j) {
+      M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j));
+      M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i));
+      M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j));
+      Vec3 Xdiff = X_world.col(i) - X_world.col(j);
+      double center_to_point_distance = Xdiff.norm();
+      M(row, num_m_columns - 1) =
+          - center_to_point_distance * center_to_point_distance;
+      ij_index(row, 0) = i;
+      ij_index(row, 1) = j;
+      ++row;
+    }
+    ij_index(i + num_m_rows, 0) = i;
+    ij_index(i + num_m_rows, 1) = i;
+  }
+
+  int num_lambda = num_points + 1;  // Dimension of the null space of M.
+  Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0, 
+                                                           num_m_rows,
+                                                           num_m_columns,
+                                                           num_lambda);
+
+  // TODO(vess): The number of constraint equations in K (num_k_rows) must be
+  // (num_points + 1) * (num_points + 2)/2. This creates a performance issue
+  // for more than 4 points. It is fine for 4 points at the moment with 18
+  // instead of 15 equations.
+  int num_k_rows = num_m_rows + num_points *
+                   (num_points*(num_points-1)/2 - num_points+1);
+  int num_k_columns = num_lambda * (num_lambda + 1) / 2;
+  Mat K(num_k_rows, num_k_columns);
+  K.setZero();
+
+  // Construct the first part of the K matrix corresponding to (t_ii, t_jk) for
+  // i != j.
+  int counter_k_row = 0;
+  for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
+    for (int idx2 = 0; idx2 < num_m_rows; ++idx2) {
+
+      unsigned int i = ij_index(idx1, 0);
+      unsigned int j = ij_index(idx2, 0);
+      unsigned int k = ij_index(idx2, 1);
+
+      if( i != j && i != k ){
+        int idx3 = IJToPointIndex(i, j, num_points);
+        int idx4 = IJToPointIndex(i, k, num_points);
+
+        K.row(counter_k_row) =
+            MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
+                               V.row(idx3).transpose() * V.row(idx4),
+                               num_k_columns,
+                               num_lambda);
+        ++counter_k_row;
+      }
+    }
+  }
+
+  // Construct the second part of the K matrix corresponding to (t_ii,t_jk) for
+  // j==k.
+  for (int idx1 = num_m_rows; idx1 < num_tt_variables; ++idx1) {
+    for (int idx2 = idx1 + 1; idx2 < num_tt_variables; ++idx2) {
+      unsigned int i = ij_index(idx1, 0);
+      unsigned int j = ij_index(idx2, 0);
+      unsigned int k = ij_index(idx2, 1);
+
+      int idx3 = IJToPointIndex(i, j, num_points);
+      int idx4 = IJToPointIndex(i, k, num_points);
+
+      K.row(counter_k_row) =
+          MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)-
+                             V.row(idx3).transpose() * V.row(idx4),
+                             num_k_columns,
+                             num_lambda);
+      ++counter_k_row;
+    }
+  }
+  Vec L_sq = K.jacobiSvd(Eigen::ComputeFullV).matrixV().col(num_k_columns - 1);
+
+  // Pivot on the largest element for numerical stability. Afterwards recover
+  // the sign of the lambda solution.
+  double max_L_sq_value = fabs(L_sq(IJToIndex(0, 0, num_lambda)));
+  int max_L_sq_index = 1;
+  for (int i = 1; i < num_lambda; ++i) {
+    double abs_sq_value = fabs(L_sq(IJToIndex(i, i, num_lambda)));
+    if (max_L_sq_value < abs_sq_value) {
+      max_L_sq_value = abs_sq_value;
+      max_L_sq_index = i;
+    }
+  }
+  // Ensure positiveness of the largest value corresponding to lambda_ii.
+  L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index,
+                                    max_L_sq_index,
+                                    num_lambda)));
+  
+  
+  Vec L(num_lambda);
+  L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index,
+                                          max_L_sq_index,
+                                          num_lambda)));
+  
+  for (int i = 0; i < num_lambda; ++i) {
+    if (i != max_L_sq_index) {
+      L(i) = L_sq(IJToIndex(max_L_sq_index, i, num_lambda)) / L(max_L_sq_index);
+    }
+  }
+
+  // Correct the scale using the fact that the last constraint is equal to 1.
+  L = L / (V.row(num_m_columns - 1).dot(L));
+  Vec X = V * L;
+  
+  // Recover the distances from the camera center to the 3D points Q.
+  Vec d(num_points);
+  d.setZero();
+  for (int c_point = num_m_rows; c_point < num_tt_variables; ++c_point) {
+    d(c_point - num_m_rows) = sqrt(X(c_point));
+  }
+
+  // Create the 3D points in the camera system.
+  Mat X_cam(3, num_points);
+  for (int c_point = 0; c_point < num_points; ++c_point ) {
+    X_cam.col(c_point) = d(c_point) * x_camera_unit.col(c_point);
+  }
+  // Recover the camera translation and rotation.
+  AbsoluteOrientation(X_world, X_cam, R, t);
+}
+
+// Selects 4 virtual control points using mean and PCA.
+void SelectControlPoints(const Mat3X &X_world, 
+                         Mat *X_centered, 
+                         Mat34 *X_control_points) {
+  size_t num_points = X_world.cols();
+
+  // The first virtual control point, C0, is the centroid.
+  Vec mean, variance;
+  MeanAndVarianceAlongRows(X_world, &mean, &variance);
+  X_control_points->col(0) = mean;
+
+  // Computes PCA
+  X_centered->resize (3, num_points);
+  for (size_t c = 0; c < num_points; c++) {
+    X_centered->col(c) = X_world.col (c) - mean;
+  }
+  Mat3 X_centered_sq = (*X_centered) * X_centered->transpose();
+  Eigen::JacobiSVD<Mat3> X_centered_sq_svd(X_centered_sq, Eigen::ComputeFullU);
+  Vec3 w = X_centered_sq_svd.singularValues();
+  Mat3 u = X_centered_sq_svd.matrixU();
+  for (size_t c = 0; c < 3; c++) {
+    double k = sqrt (w (c) / num_points);
+    X_control_points->col (c + 1) = mean + k * u.col (c);
+  }
+}
+
+// Computes the barycentric coordinates for all real points
+void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, 
+                                   const Mat34 &X_control_points,
+                                   Mat4X *alphas) {
+  size_t num_points = X_world_centered.cols();
+  Mat3 C2 ;
+  for (size_t c = 1; c < 4; c++) {
+    C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0);
+  }
+
+  Mat3 C2inv = C2.inverse();
+  Mat3X a = C2inv * X_world_centered;
+
+  alphas->resize(4, num_points);
+  alphas->setZero();
+  alphas->block(1, 0, 3, num_points) = a;
+  for (size_t c = 0; c < num_points; c++) {
+    (*alphas)(0, c) = 1.0 - alphas->col(c).sum();
+  }
+}
+
+// Estimates the coordinates of all real points in the camera coordinate frame
+void ComputePointsCoordinatesInCameraFrame(
+    const Mat4X &alphas, 
+    const Vec4 &betas,
+    const Eigen::Matrix<double, 12, 12> &U,
+    Mat3X *X_camera) {
+  size_t num_points = alphas.cols();
+
+  // Estimates the control points in the camera reference frame.
+  Mat34 C2b; C2b.setZero();
+  for (size_t cu = 0; cu < 4; cu++) {
+    for (size_t c = 0; c < 4; c++) {
+      C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose();
+    }
+  }
+
+  // Estimates the 3D points in the camera reference frame
+  X_camera->resize(3, num_points);
+  for (size_t c = 0; c < num_points; c++) {
+    X_camera->col(c) = C2b * alphas.col(c);
+  }
+
+  // Check the sign of the z coordinate of the points (should be positive)
+  uint num_z_neg = 0;
+  for (size_t i = 0; i < X_camera->cols(); ++i) {
+    if ((*X_camera)(2,i) < 0) {
+      num_z_neg++;
+    }
+  }
+
+  // If more than 50% of z are negative, we change the signs
+  if (num_z_neg > 0.5 * X_camera->cols()) {
+    C2b = -C2b;
+    *X_camera = -(*X_camera);
+  }    
+}
+
+bool EuclideanResectionEPnP(const Mat2X &x_camera,
+                            const Mat3X &X_world, 
+                            Mat3 *R, Vec3 *t) {
+  CHECK(x_camera.cols() == X_world.cols());
+  CHECK(x_camera.cols() > 3);
+  size_t num_points = X_world.cols();
+  // Select the control points.
+  Mat34 X_control_points;
+  Mat X_centered;
+  SelectControlPoints(X_world, &X_centered, &X_control_points);
+  
+  // Compute the barycentric coordinates.
+  Mat4X alphas(4, num_points);
+  ComputeBarycentricCoordinates(X_centered, X_control_points, &alphas);
+   
+  // Estimates the M matrix with the barycentric coordinates
+  Mat M(2 * num_points, 12);
+  Eigen::Matrix<double, 2, 12> sub_M;
+  for (size_t c = 0; c < num_points; c++) {
+    double a0 = alphas(0, c);
+    double a1 = alphas(1, c);
+    double a2 = alphas(2, c);
+    double a3 = alphas(3, c);
+    double ui = x_camera(0, c);
+    double vi = x_camera(1, c);
+    M.block(2*c, 0, 2, 12) << a0, 0, 
+                              a0*(-ui), a1, 0,
+                              a1*(-ui), a2, 0, 
+                              a2*(-ui), a3, 0,
+                              a3*(-ui), 0, 
+                              a0, a0*(-vi), 0,
+                              a1, a1*(-vi), 0,
+                              a2, a2*(-vi), 0,
+                              a3, a3*(-vi);
+  }
+  
+  // TODO(julien): Avoid the transpose by rewriting the u2.block() calls.
+  Eigen::JacobiSVD<Mat> MtMsvd(M.transpose()*M, Eigen::ComputeFullU);
+  Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose();
+
+  // Estimate the L matrix.
+  Eigen::Matrix<double, 6, 3> dv1;
+  Eigen::Matrix<double, 6, 3> dv2;
+  Eigen::Matrix<double, 6, 3> dv3;
+  Eigen::Matrix<double, 6, 3> dv4;
+
+  dv1.row(0) = u2.block(11, 0, 1, 3) - u2.block(11, 3, 1, 3);
+  dv1.row(1) = u2.block(11, 0, 1, 3) - u2.block(11, 6, 1, 3);
+  dv1.row(2) = u2.block(11, 0, 1, 3) - u2.block(11, 9, 1, 3);
+  dv1.row(3) = u2.block(11, 3, 1, 3) - u2.block(11, 6, 1, 3);
+  dv1.row(4) = u2.block(11, 3, 1, 3) - u2.block(11, 9, 1, 3);
+  dv1.row(5) = u2.block(11, 6, 1, 3) - u2.block(11, 9, 1, 3);
+  dv2.row(0) = u2.block(10, 0, 1, 3) - u2.block(10, 3, 1, 3);
+  dv2.row(1) = u2.block(10, 0, 1, 3) - u2.block(10, 6, 1, 3);
+  dv2.row(2) = u2.block(10, 0, 1, 3) - u2.block(10, 9, 1, 3);
+  dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3);
+  dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3);
+  dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3);
+  dv3.row(0) = u2.block( 9, 0, 1, 3) - u2.block( 9, 3, 1, 3);
+  dv3.row(1) = u2.block( 9, 0, 1, 3) - u2.block( 9, 6, 1, 3);
+  dv3.row(2) = u2.block( 9, 0, 1, 3) - u2.block( 9, 9, 1, 3);
+  dv3.row(3) = u2.block( 9, 3, 1, 3) - u2.block( 9, 6, 1, 3);
+  dv3.row(4) = u2.block( 9, 3, 1, 3) - u2.block( 9, 9, 1, 3);
+  dv3.row(5) = u2.block( 9, 6, 1, 3) - u2.block( 9, 9, 1, 3);
+  dv4.row(0) = u2.block( 8, 0, 1, 3) - u2.block( 8, 3, 1, 3);
+  dv4.row(1) = u2.block( 8, 0, 1, 3) - u2.block( 8, 6, 1, 3);
+  dv4.row(2) = u2.block( 8, 0, 1, 3) - u2.block( 8, 9, 1, 3);
+  dv4.row(3) = u2.block( 8, 3, 1, 3) - u2.block( 8, 6, 1, 3);
+  dv4.row(4) = u2.block( 8, 3, 1, 3) - u2.block( 8, 9, 1, 3);
+  dv4.row(5) = u2.block( 8, 6, 1, 3) - u2.block( 8, 9, 1, 3);
+
+  Eigen::Matrix<double, 6, 10> L;
+  for (size_t r = 0; r < 6; r++) {
+    L.row(r) << dv1.row(r).dot(dv1.row(r)),
+          2.0 * dv1.row(r).dot(dv2.row(r)),
+                dv2.row(r).dot(dv2.row(r)),
+          2.0 * dv1.row(r).dot(dv3.row(r)),
+          2.0 * dv2.row(r).dot(dv3.row(r)),
+                dv3.row(r).dot(dv3.row(r)),
+          2.0 * dv1.row(r).dot(dv4.row(r)),
+          2.0 * dv2.row(r).dot(dv4.row(r)),
+          2.0 * dv3.row(r).dot(dv4.row(r)),
+                dv4.row(r).dot(dv4.row(r));
+  }  
+  Vec6 rho;
+  rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(),
+         (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(),
+         (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(),
+         (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(),
+         (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(),
+         (X_control_points.col(2) - X_control_points.col(3)).squaredNorm();
+  // There are three possible solutions based on the three approximations of L
+  // (betas). Below, each one is solved for then the best one is chosen.
+  Mat3X X_camera;
+  Mat3 K; K.setIdentity();
+  vector<Mat3> Rs(3);
+  vector<Vec3> ts(3);
+  Vec rmse(3);
+
+  // TODO(julien): Document where the "1e-3" magical constant comes from below.
+
+  // Find the first possible solution for R, t corresponding to:
+  // Betas          = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+  // Betas_approx_1 = [b00 b01     b02         b03]
+  Vec4 betas = Vec4::Zero();
+  Eigen::Matrix<double, 6, 4> l_6x4;
+  for (size_t r = 0; r < 6; r++) {
+    l_6x4.row(r) << L(r, 0), L(r, 1), L(r, 3), L(r, 6); 
+  }
+  Eigen::JacobiSVD<Mat> svd_of_l4(l_6x4, 
+                                  Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec4 b4 = svd_of_l4.solve(rho);
+  if ((l_6x4 * b4).isApprox(rho, 1e-3)) {
+    if (b4(0) < 0) {
+      b4 = -b4;
+    } 
+    b4(0) =  std::sqrt(b4(0));
+    betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0);
+    ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+    AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]);
+    rmse(0) = RootMeanSquareError(x_camera, X_world, K, Rs[0], ts[0]);
+  } else {
+    LOG(ERROR) << "First approximation of beta not good enough.";
+    ts[0].setZero();
+    rmse(0) = std::numeric_limits<double>::max();
+  }
+  // Find the second possible solution for R, t corresponding to:
+  // Betas          = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+  // Betas_approx_2 = [b00 b01 b11]
+  betas.setZero();
+  Eigen::Matrix<double, 6, 3> l_6x3;
+  l_6x3 = L.block(0, 0, 6, 3);
+  Eigen::JacobiSVD<Mat> svdOfL3(l_6x3, 
+                                Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec3 b3 = svdOfL3.solve(rho);
+  VLOG(2) << " rho = " << rho;
+  VLOG(2) << " l_6x3 * b3 = " << l_6x3 * b3;
+  if ((l_6x3 * b3).isApprox(rho, 1e-3)) {
+    if (b3(0) < 0) {
+      betas(0) = std::sqrt(-b3(0));
+      betas(1) = (b3(2) < 0) ? std::sqrt(-b3(2)) : 0;
+    } else {
+      betas(0) = std::sqrt(b3(0));
+      betas(1) = (b3(2) > 0) ? std::sqrt(b3(2)) : 0;
+    }
+    if (b3(1) < 0) {
+      betas(0) = -betas(0);
+    }
+    betas(2) = 0;
+    betas(3) = 0;
+    ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+    AbsoluteOrientation(X_world, X_camera, &Rs[1], &ts[1]);
+    rmse(1) = RootMeanSquareError(x_camera, X_world, K, Rs[1], ts[1]);
+  } else {
+    LOG(ERROR) << "Second approximation of beta not good enough.";
+    ts[1].setZero();
+    rmse(1) = std::numeric_limits<double>::max();
+  }
+  
+  // Find the third possible solution for R, t corresponding to:
+  // Betas          = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33]
+  // Betas_approx_3 = [b00 b01 b11 b02 b12]
+  betas.setZero();
+  Eigen::Matrix<double, 6, 5> l_6x5;
+  l_6x5 = L.block(0, 0, 6, 5);
+  Eigen::JacobiSVD<Mat> svdOfL5(l_6x5, 
+                                Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec5 b5 = svdOfL5.solve(rho);
+  if ((l_6x5 * b5).isApprox(rho, 1e-3)) {
+    if (b5(0) < 0) {
+      betas(0) = std::sqrt(-b5(0));
+      if (b5(2) < 0) {
+        betas(1) = std::sqrt(-b5(2));
+      } else {
+        b5(2) = 0;
+      }
+    } else {
+      betas(0) = std::sqrt(b5(0));
+      if (b5(2) > 0) {
+        betas(1) = std::sqrt(b5(2));
+      } else {
+        b5(2) = 0;
+      }
+    }
+    if (b5(1) < 0) {
+      betas(0) = -betas(0);
+    }
+    betas(2) = b5(3) / betas(0);
+    betas(3) = 0;
+    ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera);
+    AbsoluteOrientation(X_world, X_camera, &Rs[2], &ts[2]);
+    rmse(2) = RootMeanSquareError(x_camera, X_world, K, Rs[2], ts[2]);
+  } else {
+    LOG(ERROR) << "Third approximation of beta not good enough.";
+    ts[2].setZero();
+    rmse(2) = std::numeric_limits<double>::max();
+  }
+  
+  // Finally, with all three solutions, select the (R, t) with the best RMSE.
+  VLOG(2) << "RMSE for solution 0: " << rmse(0);
+  VLOG(2) << "RMSE for solution 1: " << rmse(0);
+  VLOG(2) << "RMSE for solution 2: " << rmse(0);
+  size_t n = 0;
+  if (rmse(1) < rmse(0)) {
+    n = 1;
+  }
+  if (rmse(2) < rmse(n)) {
+    n = 2;
+  }
+  if (rmse(n) == std::numeric_limits<double>::max()) {
+    LOG(ERROR) << "All three possibilities failed. Reporting failure.";
+    return false;
+  }
+
+  VLOG(1) << "RMSE for best solution #" << n << ": " << rmse(n);
+  *R = Rs[n];
+  *t = ts[n];
+
+  // TODO(julien): Improve the solutions with non-linear refinement.
+  return true;
+}
+
+} // namespace resection
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/extern/libmv/libmv/multiview/euclidean_resection.h
new file mode 100644 (file)
index 0000000..08fa3d9
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright (c) 2010 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
+#define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/multiview/projection.h"
+
+namespace libmv {
+namespace euclidean_resection {
+  
+enum ResectionMethod {
+  RESECTION_ANSAR_DANIILIDIS,
+  RESECTION_EPNP,
+};
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera
+ * from 4 or more 3D points and their normalized images.
+ *
+ * \param x_camera  Image points in normalized camera coordinates e.g. x_camera
+ *                   = inv(K) * x_image.
+ * \param X_world   3D points in the world coordinate system
+ * \param R         Solution for the camera rotation matrix
+ * \param t         Solution for the camera translation vector
+ * \param method    The resection method to use.
+ */
+bool EuclideanResection(const Mat2X &x_camera, 
+                        const Mat3X &X_world,
+                        Mat3 *R, Vec3 *t,
+                        ResectionMethod method = RESECTION_EPNP);
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera
+ * from 4 or more 3D points and their images.
+ *
+ * \param x_image   Image points in non-normalized image coordinates. The
+ *                  coordates are laid out one per row. The matrix can be Nx2
+ *                  or Nx3 for euclidean or homogenous 2D coordinates.
+ * \param X_world   3D points in the world coordinate system
+ * \param K         Intrinsic parameters camera matrix
+ * \param R         Solution for the camera rotation matrix
+ * \param t         Solution for the camera translation vector
+ * \param method    Resection method
+ */
+bool EuclideanResection(const Mat &x_image, 
+                        const Mat3X &X_world,
+                        const Mat3 &K,
+                        Mat3 *R, Vec3 *t,
+                        ResectionMethod method = RESECTION_EPNP);
+
+/**
+ * The absolute orientation algorithm recovers the transformation between a set
+ * of 3D points, X and Xp such that:
+ *
+ *           Xp = R*X + t
+ *
+ * The recovery of the absolute orientation is implemented after this article:
+ * Horn, Hilden, "Closed-form solution of absolute orientation using
+ * orthonormal matrices"
+ */
+void AbsoluteOrientation(const Mat3X &X,
+                         const Mat3X &Xp,
+                         Mat3 *R,
+                         Vec3 *t);
+
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
+ * more 3D points and their images.
+ *
+ * \param x_camera Image points in normalized camera coordinates, e.g.
+ *                 x_camera=inv(K)*x_image
+ * \param X_world  3D points in the world coordinate system
+ * \param R        Solution for the camera rotation matrix
+ * \param t        Solution for the camera translation vector
+ *
+ * This is the algorithm described in: "Linear Pose Estimation from Points or
+ * Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5.
+ */
+void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, 
+                                       const Mat3X &X_world,
+                                       Mat3 *R, Vec3 *t);
+/**
+ * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or
+ * more 3D points and their images.
+ *
+ * \param x_camera Image points in normalized camera coordinates,
+ *                 e.g. x_camera = inv(K) * x_image
+ * \param X_world 3D points in the world coordinate system
+ * \param R       Solution for the camera rotation matrix
+ * \param t       Solution for the camera translation vector
+ *
+ * This is the algorithm described in:
+ * "{EP$n$P: An Accurate $O(n)$ Solution to the P$n$P Problem", by V. Lepetit
+ * and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2
+ * \note: the non-linear optimization is not implemented here.
+ */
+bool EuclideanResectionEPnP(const Mat2X &x_camera,
+                            const Mat3X &X_world, 
+                            Mat3 *R, Vec3 *t);
+
+} // namespace euclidean_resection
+} // namespace libmv
+
+
+#endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc
new file mode 100644 (file)
index 0000000..7a6b4a0
--- /dev/null
@@ -0,0 +1,391 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
+#include "libmv/multiview/conditioning.h"
+#include "libmv/multiview/projection.h"
+#include "libmv/multiview/triangulation.h"
+#include "libmv/multiview/fundamental.h"
+
+namespace libmv {
+
+void EliminateRow(const Mat34 &P, int row, Mat *X) {
+  X->resize(2, 4);
+
+  int first_row = (row + 1) % 3;
+  int second_row = (row + 2) % 3;
+
+  for (int i = 0; i < 4; ++i) {
+    (*X)(0, i) = P(first_row, i);
+    (*X)(1, i) = P(second_row, i);
+  }
+}
+
+void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) {
+  *P1 << Mat3::Identity(), Vec3::Zero();
+  Vec3 e2;
+  Mat3 Ft = F.transpose();
+  Nullspace(&Ft, &e2);
+  *P2 << CrossProductMatrix(e2) * F, e2;
+}
+
+// Addapted from vgg_F_from_P.
+void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) {
+  Mat X[3];
+  Mat Y[3];
+  Mat XY;
+
+  for (int i = 0; i < 3; ++i) {
+    EliminateRow(P1, i, X + i);
+    EliminateRow(P2, i, Y + i);
+  }
+
+  for (int i = 0; i < 3; ++i) {
+    for (int j = 0; j < 3; ++j) {
+      VerticalStack(X[j], Y[i], &XY);
+      (*F)(i, j) = XY.determinant();
+    }
+  }
+}
+
+// HZ 11.1 pag.279 (x1 = x, x2 = x')
+// http://www.cs.unc.edu/~marc/tutorial/node54.html
+double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) {
+  DCHECK_EQ(x1.rows(), 2);
+  DCHECK_GE(x1.cols(), 8);
+  DCHECK_EQ(x1.rows(), x2.rows());
+  DCHECK_EQ(x1.cols(), x2.cols());
+
+  int n = x1.cols();
+  Mat A(n, 9);
+  for (int i = 0; i < n; ++i) {
+    A(i, 0) = x2(0, i) * x1(0, i);
+    A(i, 1) = x2(0, i) * x1(1, i);
+    A(i, 2) = x2(0, i);
+    A(i, 3) = x2(1, i) * x1(0, i);
+    A(i, 4) = x2(1, i) * x1(1, i);
+    A(i, 5) = x2(1, i);
+    A(i, 6) = x1(0, i);
+    A(i, 7) = x1(1, i);
+    A(i, 8) = 1;
+  }
+
+  Vec9 f;
+  double smaller_singular_value = Nullspace(&A, &f);
+  *F = Map<RMat3>(f.data());
+  return smaller_singular_value;
+}
+
+// HZ 11.1.1 pag.280
+void EnforceFundamentalRank2Constraint(Mat3 *F) {
+  Eigen::JacobiSVD<Mat3> USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Vec3 d = USV.singularValues();
+  d(2) = 0.0;
+  *F = USV.matrixU() * d.asDiagonal() * USV.matrixV().transpose();
+}
+
+// HZ 11.2 pag.281 (x1 = x, x2 = x')
+double NormalizedEightPointSolver(const Mat &x1,
+                                  const Mat &x2,
+                                  Mat3 *F) {
+  DCHECK_EQ(x1.rows(), 2);
+  DCHECK_GE(x1.cols(), 8);
+  DCHECK_EQ(x1.rows(), x2.rows());
+  DCHECK_EQ(x1.cols(), x2.cols());
+
+  // Normalize the data.
+  Mat3 T1, T2;
+  PreconditionerFromPoints(x1, &T1);
+  PreconditionerFromPoints(x2, &T2);
+  Mat x1_normalized, x2_normalized;
+  ApplyTransformationToPoints(x1, T1, &x1_normalized);
+  ApplyTransformationToPoints(x2, T2, &x2_normalized);
+
+  // Estimate the fundamental matrix.
+  double smaller_singular_value =
+      EightPointSolver(x1_normalized, x2_normalized, F);
+  EnforceFundamentalRank2Constraint(F);
+
+  // Denormalize the fundamental matrix.
+  *F = T2.transpose() * (*F) * T1;
+
+  return smaller_singular_value;
+}
+
+// Seven-point algorithm.
+// http://www.cs.unc.edu/~marc/tutorial/node55.html
+double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
+                                             const Mat &x2,
+                                             std::vector<Mat3> *F) {
+  DCHECK_EQ(x1.rows(), 2);
+  DCHECK_EQ(x1.cols(), 7);
+  DCHECK_EQ(x1.rows(), x2.rows());
+  DCHECK_EQ(x2.cols(), x2.cols());
+
+  // Build a 9 x n matrix from point matches, where each row is equivalent to
+  // the equation x'T*F*x = 0 for a single correspondence pair (x', x). The
+  // domain of the matrix is a 9 element vector corresponding to F. The
+  // nullspace should be rank two; the two dimensions correspond to the set of
+  // F matrices satisfying the epipolar geometry.
+  Matrix<double, 7, 9> A;
+  for (int ii = 0; ii < 7; ++ii) {
+    A(ii, 0) = x1(0, ii) * x2(0, ii);  // 0 represents x coords,
+    A(ii, 1) = x1(1, ii) * x2(0, ii);  // 1 represents y coords.
+    A(ii, 2) = x2(0, ii);
+    A(ii, 3) = x1(0, ii) * x2(1, ii);
+    A(ii, 4) = x1(1, ii) * x2(1, ii);
+    A(ii, 5) = x2(1, ii);
+    A(ii, 6) = x1(0, ii);
+    A(ii, 7) = x1(1, ii);
+    A(ii, 8) = 1.0;
+  }
+
+  // Find the two F matrices in the nullspace of A.
+  Vec9 f1, f2;
+  double s = Nullspace2(&A, &f1, &f2);
+  Mat3 F1 = Map<RMat3>(f1.data());
+  Mat3 F2 = Map<RMat3>(f2.data());
+
+  // Then, use the condition det(F) = 0 to determine F. In other words, solve
+  // det(F1 + a*F2) = 0 for a.
+  double a = F1(0, 0), j = F2(0, 0),
+         b = F1(0, 1), k = F2(0, 1),
+         c = F1(0, 2), l = F2(0, 2),
+         d = F1(1, 0), m = F2(1, 0),
+         e = F1(1, 1), n = F2(1, 1),
+         f = F1(1, 2), o = F2(1, 2),
+         g = F1(2, 0), p = F2(2, 0),
+         h = F1(2, 1), q = F2(2, 1),
+         i = F1(2, 2), r = F2(2, 2);
+
+  // Run fundamental_7point_coeffs.py to get the below coefficients.
+  // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N.
+  double P[4] = {
+    a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g,
+    a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k -
+    a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j,
+    a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n -
+    a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m,
+    j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p,
+  };
+
+  // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0.
+  double roots[3];
+  int num_roots = SolveCubicPolynomial(P, roots);
+
+  // Build the fundamental matrix for each solution.
+  for (int kk = 0; kk < num_roots; ++kk)  {
+    F->push_back(F1 + roots[kk] * F2);
+  }
+  return s;
+}
+
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+                                            const Mat &x2,
+                                            std::vector<Mat3> *F) {
+  DCHECK_EQ(x1.rows(), 2);
+  DCHECK_GE(x1.cols(), 7);
+  DCHECK_EQ(x1.rows(), x2.rows());
+  DCHECK_EQ(x1.cols(), x2.cols());
+
+  // Normalize the data.
+  Mat3 T1, T2;
+  PreconditionerFromPoints(x1, &T1);
+  PreconditionerFromPoints(x2, &T2);
+  Mat x1_normalized, x2_normalized;
+  ApplyTransformationToPoints(x1, T1, &x1_normalized);
+  ApplyTransformationToPoints(x2, T2, &x2_normalized);
+
+  // Estimate the fundamental matrix.
+  double smaller_singular_value =
+    FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F));
+
+  for (int k = 0; k < F->size(); ++k) {
+    Mat3 & Fmat = (*F)[k];
+    // Denormalize the fundamental matrix.
+    Fmat = T2.transpose() * Fmat * T1;
+  }
+  return smaller_singular_value;
+}
+
+void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) {
+  *F_normalized = F / FrobeniusNorm(F);
+  if ((*F_normalized)(2, 2) < 0) {
+    *F_normalized *= -1;
+  }
+}
+
+double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+  Vec3 x(x1(0), x1(1), 1.0);
+  Vec3 y(x2(0), x2(1), 1.0);
+
+  Vec3 F_x = F * x;
+  Vec3 Ft_y = F.transpose() * y;
+  double y_F_x = y.dot(F_x);
+
+  return Square(y_F_x) / (  F_x.head<2>().squaredNorm()
+                          + Ft_y.head<2>().squaredNorm());
+}
+
+double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
+  Vec3 x(x1(0), x1(1), 1.0);
+  Vec3 y(x2(0), x2(1), 1.0);
+
+  Vec3 F_x = F * x;
+  Vec3 Ft_y = F.transpose() * y;
+  double y_F_x = y.dot(F_x);
+
+  return Square(y_F_x) * (  1 / F_x.head<2>().squaredNorm()
+                          + 1 / Ft_y.head<2>().squaredNorm());
+}
+
+// HZ 9.6 pag 257 (formula 9.12)
+void EssentialFromFundamental(const Mat3 &F,
+                              const Mat3 &K1,
+                              const Mat3 &K2,
+                              Mat3 *E) {
+  *E = K2.transpose() * F * K1;
+}
+
+// HZ 9.6 pag 257 (formula 9.12)
+// Or http://ai.stanford.edu/~birch/projective/node20.html
+void FundamentalFromEssential(const Mat3 &E,
+                              const Mat3 &K1,
+                              const Mat3 &K2,
+                              Mat3 *F)  {
+  *F = K2.inverse().transpose() * E * K1.inverse();
+}
+
+void RelativeCameraMotion(const Mat3 &R1,
+                          const Vec3 &t1,
+                          const Mat3 &R2,
+                          const Vec3 &t2,
+                          Mat3 *R,
+                          Vec3 *t) {
+  *R = R2 * R1.transpose();
+  *t = t2 - (*R) * t1;
+}
+
+// HZ 9.6 pag 257
+void EssentialFromRt(const Mat3 &R1,
+                     const Vec3 &t1,
+                     const Mat3 &R2,
+                     const Vec3 &t2,
+                     Mat3 *E) {
+  Mat3 R;
+  Vec3 t;
+  RelativeCameraMotion(R1, t1, R2, t2, &R, &t);
+  Mat3 Tx = CrossProductMatrix(t);
+  *E = Tx * R;
+}
+
+// HZ 9.6 pag 259 (Result 9.19)
+void MotionFromEssential(const Mat3 &E,
+                         std::vector<Mat3> *Rs,
+                         std::vector<Vec3> *ts) {
+  Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
+  Mat3 U =  USV.matrixU();
+  Vec3 d =  USV.singularValues();
+  Mat3 Vt = USV.matrixV().transpose();
+
+  // Last column of U is undetermined since d = (a a 0).
+  if (U.determinant() < 0) {
+    U.col(2) *= -1;
+  }
+  // Last row of Vt is undetermined since d = (a a 0).
+  if (Vt.determinant() < 0) {
+    Vt.row(2) *= -1;
+  }
+
+  Mat3 W;
+  W << 0, -1,  0,
+       1,  0,  0,
+       0,  0,  1;
+
+  Mat3 U_W_Vt = U * W * Vt;
+  Mat3 U_Wt_Vt = U * W.transpose() * Vt;
+
+  Rs->resize(4);
+  (*Rs)[0] = U_W_Vt;
+  (*Rs)[1] = U_W_Vt;
+  (*Rs)[2] = U_Wt_Vt;
+  (*Rs)[3] = U_Wt_Vt;
+
+  ts->resize(4);
+  (*ts)[0] =  U.col(2);
+  (*ts)[1] = -U.col(2);
+  (*ts)[2] =  U.col(2);
+  (*ts)[3] = -U.col(2);
+}
+
+int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
+                                      const std::vector<Vec3> &ts,
+                                      const Mat3 &K1,
+                                      const Vec2 &x1,
+                                      const Mat3 &K2,
+                                      const Vec2 &x2) {
+  DCHECK_EQ(4, Rs.size());
+  DCHECK_EQ(4, ts.size());
+
+  Mat34 P1, P2;
+  Mat3 R1;
+  Vec3 t1;
+  R1.setIdentity();
+  t1.setZero();
+  P_From_KRt(K1, R1, t1, &P1);
+  for (int i = 0; i < 4; ++i) {
+    const Mat3 &R2 = Rs[i];
+    const Vec3 &t2 = ts[i];
+    P_From_KRt(K2, R2, t2, &P2);
+    Vec3 X;
+    TriangulateDLT(P1, x1, P2, x2, &X);
+    double d1 = Depth(R1, t1, X);
+    double d2 = Depth(R2, t2, X);
+    // Test if point is front to the two cameras.
+    if (d1 > 0 && d2 > 0) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
+                                          const Mat3 &K1,
+                                          const Vec2 &x1,
+                                          const Mat3 &K2,
+                                          const Vec2 &x2,
+                                          Mat3 *R,
+                                          Vec3 *t) {
+  std::vector<Mat3> Rs;
+  std::vector<Vec3> ts;
+  MotionFromEssential(E, &Rs, &ts);
+  int solution = MotionFromEssentialChooseSolution(Rs, ts, K1, x1, K2, x2);
+  if (solution >= 0) {
+    *R = Rs[solution];
+    *t = ts[solution];
+    return true;
+  } else {
+    return false;
+  }
+}
+
+}  // namespace libmv
diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h
new file mode 100644 (file)
index 0000000..3f4a3b7
--- /dev/null
@@ -0,0 +1,144 @@
+// Copyright (c) 2007, 2008, 2011 libmv authors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#ifndef LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+#define LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+
+#include <vector>
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2);
+void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F);
+
+/**
+ * The normalized 8-point fundamental matrix solver.
+ */
+double NormalizedEightPointSolver(const Mat &x1,
+                                  const Mat &x2,
+                                  Mat3 *F);
+
+/**
+ * 7 points (minimal case, points coordinates must be normalized before):
+ */
+double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
+                                             const Mat &x2,
+                                             std::vector<Mat3> *F);
+
+/**
+ * 7 points (points coordinates must be in image space):
+ */
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+                                            const Mat &x2,
+                                            std::vector<Mat3> *F);
+
+/**
+ * 8 points (points coordinates must be in image space):
+ */
+double NormalizedEightPointSolver(const Mat &x1,
+                                  const Mat &x2,
+                                  Mat3 *F);
+
+/**
+ * Fundamental matrix utility function:
+ */
+void EnforceFundamentalRank2Constraint(Mat3 *F);
+
+void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
+
+/**
+ * Approximate squared reprojection errror.
+ *
+ * See page 287 of HZ equation 11.9. This avoids triangulating the point,
+ * relying only on the entries in F.
+ */
+double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Calculates the sum of the distances from the points to the epipolar lines.
+ *
+ * See page 288 of HZ equation 11.10.
+ */
+double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Compute the relative camera motion between two cameras.
+ *
+ * Given the motion parameters of two cameras, computes the motion parameters
+ * of the second one assuming the first one to be at the origin.
+ * If T1 and T2 are the camera motions, the computed relative motion is
+ *   T = T2 T1^{-1}
+ */
+void RelativeCameraMotion(const Mat3 &R1,
+                          const Vec3 &t1,
+                          const Mat3 &R2,
+                          const Vec3 &t2,
+                          Mat3 *R,
+                          Vec3 *t);
+
+void EssentialFromFundamental(const Mat3 &F,
+                              const Mat3 &K1,
+                              const Mat3 &K2,
+                              Mat3 *E);
+
+void FundamentalFromEssential(const Mat3 &E,
+                              const Mat3 &K1,
+                              const Mat3 &K2,
+                              Mat3 *F);
+
+void EssentialFromRt(const Mat3 &R1,
+                     const Vec3 &t1,
+                     const Mat3 &R2,
+                     const Vec3 &t2,
+                     Mat3 *E);
+
+void MotionFromEssential(const Mat3 &E,
+                         std::vector<Mat3> *Rs,
+                         std::vector<Vec3> *ts);
+
+/**
+ * Choose one of the four possible motion solutions from an essential matrix.
+ *
+ * Decides the right solution by checking that the triangulation of a match
+ * x1--x2 lies in front of the cameras.  See HZ 9.6 pag 259 (9.6.3 Geometrical
+ * interpretation of the 4 solutions)
+ *
+ * \return index of the right solution or -1 if no solution.
+ */
+int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
+                                      const std::vector<Vec3> &ts,
+                                      const Mat3 &K1,
+                                      const Vec2 &x1,
+                                      const Mat3 &K2,
+                                      const Vec2 &x2);
+
+bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
+                                          const Mat3 &K1,
+                                          const Vec2 &x1,
+                                          const Mat3 &K2,
+                                          const Vec2 &x2,
+                                          Mat3 *R,
+                                          Vec3 *t);
+
+}  // namespace libmv
+
+#endif  // LIBMV_MULTIVIEW_FUNDAMENTAL_H_
diff --git a/extern/libmv/libmv/multiview/nviewtriangulation.h b/extern/libmv/libmv/multiview/nviewtriangulation.h
new file mode 100644 (file)
index 0000000..b4f521f
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 libmv authors.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+// 
+// Compute a 3D position of a point from several images of it. In particular,
+// compute the projective point X in R^4 such that x = PX.
+//
+// Algorithm is the standard DLT; for derivation see appendix of Keir's thesis.
+
+#ifndef LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H
+#define LIBMV_MULTIVIEW_NVIEWTRIANGULATION_H
+
+#include "libmv/base/vector.h"
+#include "libmv/logging/logging.h"
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The
+// output, X, is a homogeneous four vectors.
+template<typename T>
+void NViewTriangulate(const Matrix<T, 2, Dynamic> &x,
+                      const vector<Matrix<T, 3, 4> > &Ps,
+                      Matrix<T, 4, 1> *X) {
+  int nviews = x.cols();
+  assert(nviews == Ps.size());
+
+  Matrix<T, Dynamic, Dynamic> design(3*nviews, 4 + nviews);
+  design.setConstant(0.0);
+  for (int i = 0; i < nviews; i++) {
+    design.template block<3, 4>(3*i, 0) = -Ps[i];
+    design(3*i + 0, 4 + i) = x(0, i);
+    design(3*i + 1, 4 + i) = x(1, i);
+    design(3*i + 2, 4 + i) = 1.0;
+  }
+  Matrix<T, Dynamic, 1>  X_and_alphas;
+  Nullspace(&design, &X_and_alphas);
+  X->resize(4);
+  *X = X_and_alphas.head(4);
+}
+
+// x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The
+// output, X, is a homogeneous four vectors.
+// This method uses the algebraic distance approximation.
+// Note that this method works better when the 2D points are normalized
+// with an isotopic normalization.
+template<typename T>
+void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic> &x,
+                               const vector<Matrix<T, 3, 4> > &Ps,
+                               Matrix<T, 4, 1> *X) {
+  int nviews = x.cols();
+  assert(nviews == Ps.size());
+
+  Matrix<T, Dynamic, 4> design(2*nviews, 4);
+  for (int i = 0; i < nviews; i++) {
+    design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i];
+  }
+  X->resize(4);
+  Nullspace(&design, X);
+}
+
+}  // namespace libmv
+
+#endif  // LIBMV_MULTIVIEW_RESECTION_H
diff --git a/extern/libmv/libmv/multiview/projection.cc b/extern/libmv/libmv/multiview/projection.cc
new file mode 100644 (file)
index 0000000..d8e4dce
--- /dev/null
@@ -0,0 +1,221 @@
+// Copyright (c) 2007, 2008 libmv authors.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS",&n