/**
 * @file LbfgsSolver.hpp
 * @author Jorge Nocedal
 * @license License BSD-3-Clause
 * @copyright 1990, Jorge Nocedal
 * @copyright 2007-2010 Naoaki Okazaki
 * @date 2019-10-06
 * @brief C library of Limited memory BFGS (L-BFGS).
 *
 * All rights reserved.
 *
 * 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.
 *
 */

#pragma once

#include <iostream>
#include <Eigen/Dense>
#include <solver/interface/NlpDescription.hpp>

namespace solver {
  /**
   * Return values of lbfgs().
   *  Roughly speaking, a negative value indicates an error.
   */
  enum {
    /** L-BFGS reaches convergence. */
    LBFGS_SUCCESS = 0,
    LBFGS_STOP,
    /** The initial variables already minimize the objective function. */
    LBFGS_ALREADY_MINIMIZED,
	/** Unknown error. */
	LBFGSERR_UNKNOWNERROR = -1024,
    /** Logic error. */
    LBFGSERR_LOGICERROR,
    /** Insufficient memory. */
    LBFGSERR_OUTOFMEMORY,
    /** Invalid number of variables specified. */
    LBFGSERR_INVALID_N,
    /** Invalid parameter lbfgs_parameter_t::epsilon specified. */
    LBFGSERR_INVALID_EPSILON,
    /** Invalid parameter lbfgs_parameter_t::past specified. */
    LBFGSERR_INVALID_TESTPERIOD,
    /** Invalid parameter lbfgs_parameter_t::delta specified. */
    LBFGSERR_INVALID_DELTA,
    /** Invalid parameter lbfgs_parameter_t::linesearch specified. */
    LBFGSERR_INVALID_LINESEARCH,
    /** Invalid parameter lbfgs_parameter_t::max_step specified. */
    LBFGSERR_INVALID_MINSTEP,
    /** Invalid parameter lbfgs_parameter_t::max_step specified. */
    LBFGSERR_INVALID_MAXSTEP,
    /** Invalid parameter lbfgs_parameter_t::ftol specified. */
    LBFGSERR_INVALID_FTOL,
    /** Invalid parameter lbfgs_parameter_t::wolfe specified. */
    LBFGSERR_INVALID_WOLFE,
    /** Invalid parameter lbfgs_parameter_t::gtol specified. */
    LBFGSERR_INVALID_GTOL,
    /** Invalid parameter lbfgs_parameter_t::xtol specified. */
    LBFGSERR_INVALID_XTOL,
    /** Invalid parameter lbfgs_parameter_t::max_linesearch specified. */
    LBFGSERR_INVALID_MAXLINESEARCH,
    /** Invalid parameter lbfgs_parameter_t::orthantwise_c specified. */
    LBFGSERR_INVALID_ORTHANTWISE,
    /** Invalid parameter lbfgs_parameter_t::orthantwise_start specified. */
    LBFGSERR_INVALID_ORTHANTWISE_START,
    /** Invalid parameter lbfgs_parameter_t::orthantwise_end specified. */
    LBFGSERR_INVALID_ORTHANTWISE_END,
    /** The line-search step went out of the interval of uncertainty. */
    LBFGSERR_OUTOFINTERVAL,
    /** A logic error occurred; alternatively, the interval of uncertainty became too small. */
    LBFGSERR_INCORRECT_TMINMAX,
    /** A rounding error occurred; alternatively, no line-search step
        satisfies the sufficient decrease and curvature conditions. */
    LBFGSERR_ROUNDING_ERROR,
    /** The line-search step became smaller than lbfgs_parameter_t::min_step. */
    LBFGSERR_MINIMUMSTEP,
    /** The line-search step became larger than lbfgs_parameter_t::max_step. */
    LBFGSERR_MAXIMUMSTEP,
    /** The line-search routine reaches the maximum number of evaluations. */
    LBFGSERR_MAXIMUMLINESEARCH,
    /** The algorithm routine reaches the maximum number of iterations. */
    LBFGSERR_MAXIMUMITERATION,
    /** Relative width of the interval of uncertainty is at most lbfgs_parameter_t::xtol. */
    LBFGSERR_WIDTHTOOSMALL,
    /** A logic error (negative line-search step) occurred. */
    LBFGSERR_INVALIDPARAMETERS,
    /** The current search direction increases the objective function value. */
    LBFGSERR_INCREASEGRADIENT,
  };

  /**
   * Line search algorithms.
   */
  enum {
    /** The default algorithm (MoreThuente method). */
    LBFGS_LINESEARCH_DEFAULT = 0,
    /** MoreThuente method proposd by More and Thuente. */
    LBFGS_LINESEARCH_MORETHUENTE = 0,
    /**
     * Backtracking method with the Armijo condition.
     *  The backtracking method finds the step length such that it satisfies
     *  the sufficient decrease (Armijo) condition,
     *    - f(x + a * d) <= f(x) + lbfgs_parameter_t::ftol * a * g(x)^T d,
     *
     *  where x is the current point, d is the current search direction, and
     *  a is the step length.
     */
    LBFGS_LINESEARCH_BACKTRACKING_ARMIJO = 1,
    /** The backtracking method with the defualt (regular Wolfe) condition. */
    LBFGS_LINESEARCH_BACKTRACKING = 2,
    /**
     * Backtracking method with regular Wolfe condition.
     *  The backtracking method finds the step length such that it satisfies
     *  both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO)
     *  and the curvature condition,
     *    - g(x + a * d)^T d >= lbfgs_parameter_t::wolfe * g(x)^T d,
     *
     *  where x is the current point, d is the current search direction, and
     *  a is the step length.
     */
    LBFGS_LINESEARCH_BACKTRACKING_WOLFE = 2,
    /**
     * Backtracking method with strong Wolfe condition.
     *  The backtracking method finds the step length such that it satisfies
     *  both the Armijo condition (LBFGS_LINESEARCH_BACKTRACKING_ARMIJO)
     *  and the following condition,
     *    - |g(x + a * d)^T d| <= lbfgs_parameter_t::wolfe * |g(x)^T d|,
     *
     *  where x is the current point, d is the current search direction, and
     *  a is the step length.
     */
    LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE = 3,
  };

  /**
   * L-BFGS optimization parameters.
   *  Call lbfgs_parameter_init() function to initialize parameters to the
   *  default values.
   */
  typedef struct {
    /**
     * The number of corrections to approximate the inverse hessian matrix.
     *  The L-BFGS routine stores the computation results of previous \ref m
     *  iterations to approximate the inverse hessian matrix of the current
     *  iteration. This parameter controls the size of the limited memories
     *  (corrections). The default value is \c 6. Values less than \c 3 are
     *  not recommended. Large values will result in excessive computing time.
     */
    int m;

    /**
     * Epsilon for convergence test.
     *  This parameter determines the accuracy with which the solution is to
     *  be found. A minimization terminates when
     *      ||g|| < \ref epsilon * max(1, ||x||),
     *  where ||.|| denotes the Euclidean (L2) norm. The default value is
     *  \c 1e-5.
     */
    double epsilon;

    /**
     * Distance for delta-based convergence test.
     *  This parameter determines the distance, in iterations, to compute
     *  the rate of decrease of the objective function. If the value of this
     *  parameter is zero, the library does not perform the delta-based
     *  convergence test. The default value is \c 0.
     */
    int past;

    /**
     * Delta for convergence test.
     *  This parameter determines the minimum rate of decrease of the
     *  objective function. The library stops iterations when the
     *  following condition is met:
     *      (f' - f) / f < \ref delta,
     *  where f' is the objective value of \ref past iterations ago, and f is
     *  the objective value of the current iteration.
     *  The default value is \c 0.
     */
    double delta;

    /**
     * The maximum number of iterations.
     *  The lbfgs() function terminates an optimization process with
     *  ::LBFGSERR_MAXIMUMITERATION status code when the iteration count
     *  exceedes this parameter. Setting this parameter to zero continues an
     *  optimization process until a convergence or error. The default value
     *  is \c 0.
     */
    int max_iterations;

    /**
     * The line search algorithm.
     *  This parameter specifies a line search algorithm to be used by the
     *  L-BFGS routine.
     */
    int linesearch;

    /**
     * The maximum number of trials for the line search.
     *  This parameter controls the number of function and gradients evaluations
     *  per iteration for the line search routine. The default value is \c 20.
     */
    int max_linesearch;

    /**
     * The minimum step of the line search routine.
     *  The default value is \c 1e-20. This value need not be modified unless
     *  the exponents are too large for the machine being used, or unless the
     *  problem is extremely badly scaled (in which case the exponents should
     *  be increased).
     */
    double min_step;

    /**
     * The maximum step of the line search.
     *  The default value is \c 1e+20. This value need not be modified unless
     *  the exponents are too large for the machine being used, or unless the
     *  problem is extremely badly scaled (in which case the exponents should
     *  be increased).
     */
    double max_step;

    /**
     * A parameter to control the accuracy of the line search routine.
     *  The default value is \c 1e-4. This parameter should be greater
     *  than zero and smaller than \c 0.5.
     */
    double ftol;

    /**
     * A coefficient for the Wolfe condition.
     *  This parameter is valid only when the backtracking line-search
     *  algorithm is used with the Wolfe condition,
     *  ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE or
     *  ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE .
     *  The default value is \c 0.9. This parameter should be greater
     *  the \ref ftol parameter and smaller than \c 1.0.
     */
    double wolfe;

    /**
     * A parameter to control the accuracy of the line search routine.
     *  The default value is \c 0.9. If the function and gradient
     *  evaluations are inexpensive with respect to the cost of the
     *  iteration (which is sometimes the case when solving very large
     *  problems) it may be advantageous to set this parameter to a small
     *  value. A typical small value is \c 0.1. This parameter shuold be
     *  greater than the \ref ftol parameter (\c 1e-4) and smaller than
     *  \c 1.0.
     */
    double gtol;

    /**
     * The machine precision for floating-point values.
     *  This parameter must be a positive value set by a client program to
     *  estimate the machine precision. The line search routine will terminate
     *  with the status code (::LBFGSERR_ROUNDING_ERROR) if the relative width
     *  of the interval of uncertainty is less than this parameter.
     */
    double xtol;
  } lbfgs_parameter_t;

  /**
   * Callback interface to provide objective function and gradient evaluations.
   *
   *  The lbfgs() function call this function to obtain the values of objective
   *  function and its gradients when needed. A client program must implement
   *  this function to evaluate the values of the objective function and its
   *  gradients, given current values of variables.
   *
   *  @param  instance    The user data sent for lbfgs() function by the client.
   *  @param  x           The current values of variables.
   *  @param  g           The gradient vector. The callback function must compute
   *                      the gradient values for the current variables.
   *  @param  n           The number of variables.
   *  @param  step        The current step of the line search routine.
   *  @retval double The value of the objective function for the current
   *                          variables.
   */
  typedef double (*lbfgs_evaluate_t)(void *instance, const double *x,
    double *g, const int n, const double step);

  /**
   * Callback interface to receive the progress of the optimization process.
   *
   *  The lbfgs() function call this function for each iteration. Implementing
   *  this function, a client program can store or display the current progress
   *  of the optimization process.
   *
   *  @param  instance    The user data sent for lbfgs() function by the client.
   *  @param  x           The current values of variables.
   *  @param  g           The current gradient values of variables.
   *  @param  fx          The current value of the objective function.
   *  @param  xnorm       The Euclidean norm of the variables.
   *  @param  gnorm       The Euclidean norm of the gradients.
   *  @param  step        The line-search step used for this iteration.
   *  @param  n           The number of variables.
   *  @param  k           The iteration count.
   *  @param  ls          The number of evaluations called for this iteration.
   *  @retval int         Zero to continue the optimization process. Returning a
   *                      non-zero value will cancel the optimization process.
   */
  typedef int (*lbfgs_progress_t)(void *instance, const double *x,
    const double *g, const double fx, const double xnorm,
    const double gnorm, const double step, int n, int k, int ls);

  /*
  A user must implement a function compatible with ::lbfgs_evaluate_t (evaluation
  callback) and pass the pointer to the callback function to lbfgs() arguments.
  Similarly, a user can implement a function compatible with ::lbfgs_progress_t
  (progress callback) to obtain the current progress (e.g., variables, function
  value, ||G||, etc) and to cancel the iteration process if necessary.
  Implementation of a progress callback is optional: a user can pass \c NULL if
  progress notification is not necessary.

  In addition, a user must preserve two requirements:
    - The number of variables must be multiples of 16 (this is not 4).
    - The memory block of variable array ::x must be aligned to 16.

  This algorithm terminates an optimization
  when:

    ||G|| < \epsilon \cdot \max(1, ||x||) .

  In this formula, ||.|| denotes the Euclidean norm.
  */

  /**
   * Start a L-BFGS optimization.
   *
   *  @param  n           The number of variables.
   *  @param  x           The array of variables. A client program can set
   *                      default values for the optimization and receive the
   *                      optimization result through this array. This array
   *                      must be allocated by ::lbfgs_malloc function
   *                      for libLBFGS built with SSE/SSE2 optimization routine
   *                      enabled. The library built without SSE/SSE2
   *                      optimization does not have such a requirement.
   *  @param  ptr_fx      The pointer to the variable that receives the final
   *                      value of the objective function for the variables.
   *                      This argument can be set to \c NULL if the final
   *                      value of the objective function is unnecessary.
   *  @param  proc_evaluate   The callback function to provide function and
   *                          gradient evaluations given a current values of
   *                          variables. A client program must implement a
   *                          callback function compatible with \ref
   *                          lbfgs_evaluate_t and pass the pointer to the
   *                          callback function.
   *  @param  proc_progress   The callback function to receive the progress
   *                          (the number of iterations, the current value of
   *                          the objective function) of the minimization
   *                          process. This argument can be set to \c NULL if
   *                          a progress report is unnecessary.
   *  @param  instance    A user data for the client program. The callback
   *                      functions will receive the value of this argument.
   *  @param  param       The pointer to a structure representing parameters for
   *                      L-BFGS optimization. A client program can set this
   *                      parameter to \c NULL to use the default parameters.
   *                      Call lbfgs_parameter_init() function to fill a
   *                      structure with the default values.
   *  @retval int         The status code. This function returns zero if the
   *                      minimization process terminates without an error. A
   *                      non-zero value indicates an error.
   */
  int lbfgs(int n, double *x, double *ptr_fx,
    lbfgs_evaluate_t proc_evaluate, lbfgs_progress_t proc_progress,
    void *instance, lbfgs_parameter_t *param);

  /**
   * Initialize L-BFGS parameters to the default values.
   *
   *  Call this function to fill a parameter structure with the default values
   *  and overwrite parameter values if necessary.
   *
   *  @param  param       The pointer to the parameter structure.
   */
  void lbfgs_parameter_init(lbfgs_parameter_t *param);

  /**
   * Allocate an array for variables.
   *
   *  This function allocates an array of variables for the convenience of
   *  ::lbfgs function; the function has a requreiemt for a variable array
   *  when libLBFGS is built with SSE/SSE2 optimization routines. A user does
   *  not have to use this function for libLBFGS built without SSE/SSE2
   *  optimization.
   *
   *  @param  n           The number of variables.
   */
  double* lbfgs_malloc(int n);

  /**
   * Free an array of variables.
   *
   *  @param  x           The array of variables allocated by ::lbfgs_malloc
   *                      function.
   */
  void lbfgs_free(double *x);

  /*
   *  LBFGS Interface Class
   */
  class LbfgsSolver
  {
    public:
	  LbfgsSolver();
      virtual ~LbfgsSolver(){}

      bool initialize(NlpDescription* nlproblem, double constraints_weight = 1.);
      void optimize();

      bool& verbose() { return verbose_; }
      lbfgs_parameter_t& opt_params() { return opt_params_; }

    private:
      // definition of cost evaluation
      static double delegate_evaluate(void *instance, const double *x, double *g, const int n, const double step );
      double evaluate(void *instance, const double *x, double *g, const int n, const double step );
      double evaluate_objective_function(const double* eig_x);

      // definition of how to show progress of the optimization
      static int delegate_progress(void *instance, const double *x, const double *g, const double fx, const double xnorm,
  		                           const double gnorm, const double step, int n, int k, int ls );
      int progress(const double *x, const double *g, double fx, double xnorm, double gnorm, int n, int k );

    private:
      NlpDescription* nlproblem_;
      double constraints_weight_;
      bool verbose_, initialized_;
      lbfgs_parameter_t opt_params_;
      int nvars_, ncons_, *user_info_, opt_status_, length_of_address_to_this_;
  };

}
/** @} */

/**
@mainpage libLBFGS: a library of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS)

@section intro Introduction

This library is a C port of the implementation of Limited-memory
Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal.
The original FORTRAN source code is available at:
http://www.ece.northwestern.edu/~nocedal/lbfgs.html

The L-BFGS method solves the unconstrainted minimization problem,

<pre>
    minimize F(x), x = (x1, x2, ..., xN),
</pre>

only if the objective function F(x) and its gradient G(x) are computable. The
well-known Newton's method requires computation of the inverse of the hessian
matrix of the objective function. However, the computational cost for the
inverse hessian matrix is expensive especially when the objective function
takes a large number of variables. The L-BFGS method iteratively finds a
minimizer by approximating the inverse hessian matrix by information from last
m iterations. This innovation saves the memory storage and computational time
drastically for large-scaled problems.

Among the various ports of L-BFGS, this library provides several features:
- <b>Optimization with L1-norm (Orthant-Wise Limited-memory Quasi-Newton
  (OWL-QN) method)</b>:
  In addition to standard minimization problems, the library can minimize
  a function F(x) combined with L1-norm |x| of the variables,
  {F(x) + C |x|}, where C is a constant scalar parameter. This feature is
  useful for estimating parameters of sparse log-linear models (e.g.,
  logistic regression and maximum entropy) with L1-regularization (or
  Laplacian prior).
- <b>Clean C code</b>:
  Unlike C codes generated automatically by f2c (Fortran 77 into C converter),
  this port includes changes based on my interpretations, improvements,
  optimizations, and clean-ups so that the ported code would be well-suited
  for a C code. In addition to comments inherited from the original code,
  a number of comments were added through my interpretations.
- <b>Callback interface</b>:
  The library receives function and gradient values via a callback interface.
  The library also notifies the progress of the optimization by invoking a
  callback function. In the original implementation, a user had to set
  function and gradient values every time the function returns for obtaining
  updated values.
- <b>Thread safe</b>:
  The library is thread-safe, which is the secondary gain from the callback
  interface.
- <b>Cross platform.</b> The source code can be compiled on Microsoft Visual
  Studio 2010, GNU C Compiler (gcc), etc.
- <b>Configurable precision</b>: A user can choose single-precision (float)
  or double-precision (double) accuracy by changing ::LBFGS_FLOAT macro.
- <b>SSE/SSE2 optimization</b>:
  This library includes SSE/SSE2 optimization (written in compiler intrinsics)
  for vector arithmetic operations on Intel/AMD processors. The library uses
  SSE for float values and SSE2 for double values. The SSE/SSE2 optimization
  routine is disabled by default.

This library is used by:
- <a href="http://www.chokkan.org/software/crfsuite/">CRFsuite: A fast implementation of Conditional Random Fields (CRFs)</a>
- <a href="http://www.chokkan.org/software/classias/">Classias: A collection of machine-learning algorithms for classification</a>
- <a href="http://www.public.iastate.edu/~gdancik/mlegp/">mlegp: an R package for maximum likelihood estimates for Gaussian processes</a>
- <a href="http://infmath.uibk.ac.at/~matthiasf/imaging2/">imaging2: the imaging2 class library</a>

@section download Download

- <a href="https://github.com/downloads/chokkan/liblbfgs/liblbfgs-1.10.tar.gz">Source code</a>
- <a href="https://github.com/chokkan/liblbfgs">GitHub repository</a>

libLBFGS is distributed under the term of the
<a href="http://opensource.org/licenses/mit-license.php">MIT license</a>.

@section modules Third-party modules
- <a href="http://cran.r-project.org/web/packages/lbfgs/index.html">lbfgs: Limited-memory BFGS Optimization (a wrapper for R)</a> maintained by Antonio Coppola.
- <a href="http://search.cpan.org/~laye/Algorithm-LBFGS-0.16/">Algorithm::LBFGS - Perl extension for L-BFGS</a> maintained by Lei Sun.
- <a href="http://www.cs.kuleuven.be/~bernd/yap-lbfgs/">YAP-LBFGS (an interface to call libLBFGS from YAP Prolog)</a> maintained by Bernd Gutmann.

@section changelog History
- Version 1.10 (2010-12-22):
    - Fixed compiling errors on Mac OS X; this patch was kindly submitted by
      Nic Schraudolph.
    - Reduced compiling warnings on Mac OS X; this patch was kindly submitted
      by Tamas Nepusz.
    - Replaced memalign() with posix_memalign().
    - Updated solution and project files for Microsoft Visual Studio 2010.
- Version 1.9 (2010-01-29):
    - Fixed a mistake in checking the validity of the parameters "ftol" and
      "wolfe"; this was discovered by Kevin S. Van Horn.
- Version 1.8 (2009-07-13):
    - Accepted the patch submitted by Takashi Imamichi;
      the backtracking method now has three criteria for choosing the step
      length:
        - ::LBFGS_LINESEARCH_BACKTRACKING_ARMIJO: sufficient decrease (Armijo)
          condition only
        - ::LBFGS_LINESEARCH_BACKTRACKING_WOLFE: regular Wolfe condition
          (sufficient decrease condition + curvature condition)
        - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE: strong Wolfe condition
    - Updated the documentation to explain the above three criteria.
- Version 1.7 (2009-02-28):
    - Improved OWL-QN routines for stability.
    - Removed the support of OWL-QN method in MoreThuente algorithm because
      it accidentally fails in early stages of iterations for some objectives.
      Because of this change, <b>the OW-LQN method must be used with the
      backtracking algorithm (::LBFGS_LINESEARCH_BACKTRACKING)</b>, or the
      library returns ::LBFGSERR_INVALID_LINESEARCH.
    - Renamed line search algorithms as follows:
        - ::LBFGS_LINESEARCH_BACKTRACKING: regular Wolfe condition.
        - ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE: regular Wolfe condition.
        - ::LBFGS_LINESEARCH_BACKTRACKING_STRONG: strong Wolfe condition.
    - Source code clean-up.
- Version 1.6 (2008-11-02):
    - Improved line-search algorithm with strong Wolfe condition, which was
      contributed by Takashi Imamichi. This routine is now default for
      ::LBFGS_LINESEARCH_BACKTRACKING. The previous line search algorithm
      with regular Wolfe condition is still available as
      ::LBFGS_LINESEARCH_BACKTRACKING_LOOSE.
    - Configurable stop index for L1-norm computation. A member variable
      ::lbfgs_parameter_t::orthantwise_end was added to specify the index
      number at which the library stops computing the L1 norm of the
      variables. This is useful to prevent some variables from being
      regularized by the OW-LQN method.
    - A sample program written in C++ (sample/sample.cpp).
- Version 1.5 (2008-07-10):
    - Configurable starting index for L1-norm computation. A member variable
      ::lbfgs_parameter_t::orthantwise_start was added to specify the index
      number from which the library computes the L1 norm of the variables.
      This is useful to prevent some variables from being regularized by the
      OWL-QN method.
    - Fixed a zero-division error when the initial variables have already
      been a minimizer (reported by Takashi Imamichi). In this case, the
      library returns ::LBFGS_ALREADY_MINIMIZED status code.
    - Defined ::LBFGS_SUCCESS status code as zero; removed unused constants,
      LBFGSFALSE and LBFGSTRUE.
    - Fixed a compile error in an implicit down-cast.
- Version 1.4 (2008-04-25):
    - Configurable line search algorithms. A member variable
      ::lbfgs_parameter_t::linesearch was added to choose either MoreThuente
      method (::LBFGS_LINESEARCH_MORETHUENTE) or backtracking algorithm
      (::LBFGS_LINESEARCH_BACKTRACKING).
    - Fixed a bug: the previous version did not compute psuedo-gradients
      properly in the line search routines for OWL-QN. This bug might quit
      an iteration process too early when the OWL-QN routine was activated
      (0 < ::lbfgs_parameter_t::orthantwise_c).
    - Configure script for POSIX environments.
    - SSE/SSE2 optimizations with GCC.
    - New functions ::lbfgs_malloc and ::lbfgs_free to use SSE/SSE2 routines
      transparently. It is uncessary to use these functions for libLBFGS built
      without SSE/SSE2 routines; you can still use any memory allocators if
      SSE/SSE2 routines are disabled in libLBFGS.
- Version 1.3 (2007-12-16):
    - An API change. An argument was added to lbfgs() function to receive the
      final value of the objective function. This argument can be set to
      \c NULL if the final value is unnecessary.
    - Fixed a null-pointer bug in the sample code (reported by Takashi Imamichi).
    - Added build scripts for Microsoft Visual Studio 2005 and GCC.
    - Added README file.
- Version 1.2 (2007-12-13):
    - Fixed a serious bug in orthant-wise L-BFGS.
      An important variable was used without initialization.
- Version 1.1 (2007-12-01):
    - Implemented orthant-wise L-BFGS.
    - Implemented lbfgs_parameter_init() function.
    - Fixed several bugs.
    - API documentation.
- Version 1.0 (2007-09-20):
    - Initial release.

@section api Documentation

- @ref liblbfgs_api "libLBFGS API"

@section sample Sample code

@include sample.c

@section ack Acknowledgements

The L-BFGS algorithm is described in:
    - Jorge Nocedal.
      Updating Quasi-Newton Matrices with Limited Storage.
      <i>Mathematics of Computation</i>, Vol. 35, No. 151, pp. 773--782, 1980.
    - Dong C. Liu and Jorge Nocedal.
      On the limited memory BFGS method for large scale optimization.
      <i>Mathematical Programming</i> B, Vol. 45, No. 3, pp. 503-528, 1989.

The line search algorithms used in this implementation are described in:
    - John E. Dennis and Robert B. Schnabel.
      <i>Numerical Methods for Unconstrained Optimization and Nonlinear
      Equations</i>, Englewood Cliffs, 1983.
    - Jorge J. More and David J. Thuente.
      Line search algorithm with guaranteed sufficient decrease.
      <i>ACM Transactions on Mathematical Software (TOMS)</i>, Vol. 20, No. 3,
      pp. 286-307, 1994.

This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN)
method presented in:
    - Galen Andrew and Jianfeng Gao.
      Scalable training of L1-regularized log-linear models.
      In <i>Proceedings of the 24th International Conference on Machine
      Learning (ICML 2007)</i>, pp. 33-40, 2007.

Special thanks go to:
    - Yoshimasa Tsuruoka and Daisuke Okanohara for technical information about
      OWL-QN
    - Takashi Imamichi for the useful enhancements of the backtracking method
    - Kevin S. Van Horn, Nic Schraudolph, and Tamas Nepusz for bug fixes

Finally I would like to thank the original author, Jorge Nocedal, who has been
distributing the effieicnt and explanatory implementation in an open source
licence.

@section reference Reference

- <a href="http://www.ece.northwestern.edu/~nocedal/lbfgs.html">L-BFGS</a> by Jorge Nocedal.
- <a href="http://research.microsoft.com/en-us/downloads/b1eb1016-1738-4bd5-83a9-370c9d498a03/default.aspx">Orthant-Wise Limited-memory Quasi-Newton Optimizer for L1-regularized Objectives</a> by Galen Andrew.
- <a href="http://chasen.org/~taku/software/misc/lbfgs/">C port (via f2c)</a> by Taku Kudo.
- <a href="http://www.alglib.net/optimization/lbfgs.php">C#/C++/Delphi/VisualBasic6 port</a> in ALGLIB.
- <a href="http://cctbx.sourceforge.net/">Computational Crystallography Toolbox</a> includes
  <a href="http://cctbx.sourceforge.net/current_cvs/c_plus_plus/namespacescitbx_1_1lbfgs.html">scitbx::lbfgs</a>.
*/


//=======================================================================
// Copyright (C) 2005-2009 Jongsoo Park <jongsoo.park -at- gmail.com>
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef BOOST_GRAPH_DOMINATOR_HPP
#define BOOST_GRAPH_DOMINATOR_HPP

#include <boost/config.hpp>
#include <deque>
#include <set>
#include <boost/graph/depth_first_search.hpp>
#include <boost/concept/assert.hpp>

// Dominator tree computation

// NOTE: This file contains modifications from the distributed Boost version to
// correctly support supplying a vertex index map to the algorithm. To
// differentiate it, it has been moved into the boost_ue2 namespace.

namespace boost_ue2 {

  using namespace boost;

  namespace detail {
    /**
     * An extended time_stamper which also records vertices for each dfs number
     */
    template<class TimeMap, class VertexVector, class TimeT, class Tag>
    class time_stamper_with_vertex_vector
      : public base_visitor<
      time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT, Tag> >
    {
    public :
      typedef Tag event_filter;
      time_stamper_with_vertex_vector(TimeMap timeMap, VertexVector& v,
                                      TimeT& t)
        : timeStamper_(timeMap, t), v_(v) { }

      template<class Graph>
      void
      operator()(const typename property_traits<TimeMap>::key_type& v,
                 const Graph& g)
      {
        timeStamper_(v, g);
        v_[timeStamper_.m_time] = v;
      }

    private :
      time_stamper<TimeMap, TimeT, Tag> timeStamper_;
      VertexVector& v_;
    };

    /**
     * A convenient way to create a time_stamper_with_vertex_vector
     */
    template<class TimeMap, class VertexVector, class TimeT, class Tag>
    time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT, Tag>
    stamp_times_with_vertex_vector(TimeMap timeMap, VertexVector& v, TimeT& t,
                                   Tag)
    {
      return time_stamper_with_vertex_vector<TimeMap, VertexVector, TimeT,
                                             Tag>(timeMap, v, t);
    }

    template<class Graph, class IndexMap, class TimeMap, class PredMap,
             class DomTreePredMap>
    class dominator_visitor
    {
      typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
      typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;

    public :
      /**
       * @param g [in] the target graph of the dominator tree
       * @param entry [in] the entry node of g
       * @param indexMap [in] the vertex index map for g
       * @param domTreePredMap [out] the immediate dominator map
       *                             (parent map in dominator tree)
       */
      dominator_visitor(const Graph& g, const Vertex& entry,
                        const IndexMap& indexMap,
                        DomTreePredMap domTreePredMap)
        : semi_(num_vertices(g)),
          ancestor_(num_vertices(g), graph_traits<Graph>::null_vertex()),
          samedom_(ancestor_),
          best_(semi_),
          semiMap_(make_iterator_property_map(semi_.begin(),
                                              indexMap)),
          ancestorMap_(make_iterator_property_map(ancestor_.begin(),
                                                  indexMap)),
          bestMap_(make_iterator_property_map(best_.begin(),
                                              indexMap)),
          buckets_(num_vertices(g)),
          bucketMap_(make_iterator_property_map(buckets_.begin(),
                                                indexMap)),
          entry_(entry),
          domTreePredMap_(domTreePredMap),
          numOfVertices_(num_vertices(g)),
          samedomMap(make_iterator_property_map(samedom_.begin(),
                                                indexMap))
      {
      }

      void
      operator()(const Vertex& n, const TimeMap& dfnumMap,
                 const PredMap& parentMap, const Graph& g)
      {
        if (n == entry_) return;

        const Vertex p(get(parentMap, n));
        Vertex s(p);

        // 1. Calculate the semidominator of n,
        // based on the semidominator thm.
        // * Semidominator thm. : To find the semidominator of a node n,
        //   consider all predecessors v of n in the CFG (Control Flow Graph).
        //  - If v is a proper ancestor of n in the spanning tree
        //    (so dfnum(v) < dfnum(n)), then v is a candidate for semi(n)
        //  - If v is a non-ancestor of n (so dfnum(v) > dfnum(n))
        //    then for each u that is an ancestor of v (or u = v),
        //    Let semi(u) be a candidate for semi(n)
        //   of all these candidates, the one with lowest dfnum is
        //   the semidominator of n.

        // For each predecessor of n
        typename graph_traits<Graph>::in_edge_iterator inItr, inEnd;
        for (boost::tie(inItr, inEnd) = in_edges(n, g); inItr != inEnd; ++inItr)
          {
            const Vertex v = source(*inItr, g);
            // To deal with unreachable nodes
            if (get(dfnumMap, v) < 0 || get(dfnumMap, v) >= numOfVertices_)
              continue;

            Vertex s2;
            if (get(dfnumMap, v) <= get(dfnumMap, n))
              s2 = v;
            else
              s2 = get(semiMap_, ancestor_with_lowest_semi_(v, dfnumMap));

            if (get(dfnumMap, s2) < get(dfnumMap, s))
              s = s2;
          }
        put(semiMap_, n, s);

        // 2. Calculation of n's dominator is deferred until
        // the path from s to n has been linked into the forest
        get(bucketMap_, s).push_back(n);
        get(ancestorMap_, n) = p;
        get(bestMap_, n) = n;

        // 3. Now that the path from p to v has been linked into
        // the spanning forest, these lines calculate the dominator of v,
        // based on the dominator thm., or else defer the calculation
        // until y's dominator is known
        // * Dominator thm. : On the spanning-tree path below semi(n) and
        //   above or including n, let y be the node
        //   with the smallest-numbered semidominator. Then,
        //
        //  idom(n) = semi(n) if semi(y)=semi(n) or
        //            idom(y) if semi(y) != semi(n)
        typename std::deque<Vertex>::iterator buckItr;
        for (buckItr = get(bucketMap_, p).begin();
             buckItr != get(bucketMap_, p).end();
             ++buckItr)
          {
            const Vertex v(*buckItr);
            const Vertex y(ancestor_with_lowest_semi_(v, dfnumMap));
            if (get(semiMap_, y) == get(semiMap_, v))
              put(domTreePredMap_, v, p);
            else
              put(samedomMap, v, y);
          }

        get(bucketMap_, p).clear();
      }

    protected :

      /**
       * Evaluate function in Tarjan's path compression
       */
      const Vertex
      ancestor_with_lowest_semi_(const Vertex& v, const TimeMap& dfnumMap)
      {
        const Vertex a(get(ancestorMap_, v));

        if (get(ancestorMap_, a) != graph_traits<Graph>::null_vertex())
          {
            const Vertex b(ancestor_with_lowest_semi_(a, dfnumMap));

            put(ancestorMap_, v, get(ancestorMap_, a));

            if (get(dfnumMap, get(semiMap_, b)) <
                get(dfnumMap, get(semiMap_, get(bestMap_, v))))
              put(bestMap_, v, b);
          }

        return get(bestMap_, v);
      }

      std::vector<Vertex> semi_, ancestor_, samedom_, best_;
      PredMap semiMap_, ancestorMap_, bestMap_;
      std::vector< std::deque<Vertex> > buckets_;

      iterator_property_map<typename std::vector<std::deque<Vertex> >::iterator,
                            IndexMap> bucketMap_;

      const Vertex& entry_;
      DomTreePredMap domTreePredMap_;
      const VerticesSizeType numOfVertices_;

    public :

      PredMap samedomMap;
    };

  } // namespace detail

  /**
   * @brief Build dominator tree using Lengauer-Tarjan algorithm.
   *                It takes O((V+E)log(V+E)) time.
   *
   * @pre dfnumMap, parentMap and verticesByDFNum have dfs results corresponding
   *      indexMap.
   *      If dfs has already run before,
   *      this function would be good for saving computations.
   * @pre Unreachable nodes must be masked as
   *      graph_traits<Graph>::null_vertex in parentMap.
   * @pre Unreachable nodes must be masked as
   *      (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap.
   *
   * @param domTreePredMap [out] : immediate dominator map (parent map
   * in dom. tree)
   *
   * @note reference Appel. p. 452~453. algorithm 19.9, 19.10.
   *
   * @todo : Optimization in Finding Dominators in Practice, Loukas Georgiadis
   */
  template<class Graph, class IndexMap, class TimeMap, class PredMap,
           class VertexVector, class DomTreePredMap>
  void
  lengauer_tarjan_dominator_tree_without_dfs
    (const Graph& g,
     const typename graph_traits<Graph>::vertex_descriptor& entry,
     const IndexMap& indexMap,
     TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum,
     DomTreePredMap domTreePredMap)
  {
    // Typedefs and concept check
    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
    typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;

    BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph> ));

    const VerticesSizeType numOfVertices = num_vertices(g);
    if (numOfVertices == 0) return;

    // 1. Visit each vertex in reverse post order and calculate sdom.
    detail::dominator_visitor<Graph, IndexMap, TimeMap, PredMap, DomTreePredMap>
      visitor(g, entry, indexMap, domTreePredMap);

    VerticesSizeType i;
    for (i = 0; i < numOfVertices; ++i)
      {
        const Vertex u(verticesByDFNum[numOfVertices - 1 - i]);
        if (u != graph_traits<Graph>::null_vertex())
          visitor(u, dfnumMap, parentMap, g);
      }

    // 2. Now all the deferred dominator calculations,
    // based on the second clause of the dominator thm., are performed
    for (i = 0; i < numOfVertices; ++i)
      {
        const Vertex n(verticesByDFNum[i]);

        if (n == entry || n == graph_traits<Graph>::null_vertex())
          continue;

        Vertex u = get(visitor.samedomMap, n);
        if (u != graph_traits<Graph>::null_vertex())
          {
            put(domTreePredMap, n, get(domTreePredMap, u));
          }
      }
  }

  /**
   * Unlike lengauer_tarjan_dominator_tree_without_dfs,
   * dfs is run in this function and
   * the result is written to dfnumMap, parentMap, vertices.
   *
   * If the result of dfs required after this algorithm,
   * this function can eliminate the need of rerunning dfs.
   */
  template<class Graph, class IndexMap, class TimeMap, class PredMap,
           class VertexVector, class DomTreePredMap>
  void
  lengauer_tarjan_dominator_tree
    (const Graph& g,
     const typename graph_traits<Graph>::vertex_descriptor& entry,
     const IndexMap& indexMap,
     TimeMap dfnumMap, PredMap parentMap, VertexVector& verticesByDFNum,
     DomTreePredMap domTreePredMap)
  {
    // Typedefs and concept check
    typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;

    BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph> ));

    // 1. Depth first visit
    const VerticesSizeType numOfVertices = num_vertices(g);
    if (numOfVertices == 0) return;

    VerticesSizeType time =
      (std::numeric_limits<VerticesSizeType>::max)();
    std::vector<default_color_type>
      colors(numOfVertices, color_traits<default_color_type>::white());
    depth_first_visit
      (g, entry,
       make_dfs_visitor
         (make_pair(record_predecessors(parentMap, on_tree_edge()),
                    detail::stamp_times_with_vertex_vector
                      (dfnumMap, verticesByDFNum, time, on_discover_vertex()))),
       make_iterator_property_map(colors.begin(), indexMap));

    // 2. Run main algorithm.
    lengauer_tarjan_dominator_tree_without_dfs(g, entry, indexMap, dfnumMap,
                                               parentMap, verticesByDFNum,
                                               domTreePredMap);
  }

  /**
   * Use vertex_index as IndexMap and make dfnumMap, parentMap, verticesByDFNum
   * internally.
   * If we don't need the result of dfs (dfnumMap, parentMap, verticesByDFNum),
   * this function would be more convenient one.
   */
  template<class Graph, class DomTreePredMap>
  void
  lengauer_tarjan_dominator_tree
    (const Graph& g,
     const typename graph_traits<Graph>::vertex_descriptor& entry,
     DomTreePredMap domTreePredMap)
  {
    // typedefs
    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
    typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
    typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
    typedef
      iterator_property_map<typename std::vector<VerticesSizeType>::iterator,
                            IndexMap> TimeMap;
    typedef
      iterator_property_map<typename std::vector<Vertex>::iterator, IndexMap>
      PredMap;

    // Make property maps
    const VerticesSizeType numOfVertices = num_vertices(g);
    if (numOfVertices == 0) return;

    const IndexMap indexMap = get(vertex_index, g);

    std::vector<VerticesSizeType> dfnum(numOfVertices, 0);
    TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));

    std::vector<Vertex> parent(numOfVertices,
                               graph_traits<Graph>::null_vertex());
    PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));

    std::vector<Vertex> verticesByDFNum(parent);

    // Run main algorithm
    lengauer_tarjan_dominator_tree(g, entry,
                                   indexMap, dfnumMap, parentMap,
                                   verticesByDFNum, domTreePredMap);
  }

  /**
   * Muchnick. p. 182, 184
   *
   * using iterative bit vector analysis
   */
  template<class Graph, class IndexMap, class DomTreePredMap>
  void
  iterative_bit_vector_dominator_tree
    (const Graph& g,
     const typename graph_traits<Graph>::vertex_descriptor& entry,
     const IndexMap& indexMap,
     DomTreePredMap domTreePredMap)
  {
    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
    typedef typename graph_traits<Graph>::vertex_iterator vertexItr;
    typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
    typedef
      iterator_property_map<typename std::vector< std::set<Vertex> >::iterator,
                            IndexMap> vertexSetMap;

    BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph> ));

    // 1. Finding dominator
    // 1.1. Initialize
    const VerticesSizeType numOfVertices = num_vertices(g);
    if (numOfVertices == 0) return;

    vertexItr vi, viend;
    boost::tie(vi, viend) = vertices(g);
    const std::set<Vertex> N(vi, viend);

    bool change = true;

    std::vector< std::set<Vertex> > dom(numOfVertices, N);
    vertexSetMap domMap(make_iterator_property_map(dom.begin(), indexMap));
    get(domMap, entry).clear();
    get(domMap, entry).insert(entry);

    while (change)
      {
        change = false;
        for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
          {
            if (*vi == entry) continue;

            std::set<Vertex> T(N);

            typename graph_traits<Graph>::in_edge_iterator inItr, inEnd;
            for (boost::tie(inItr, inEnd) = in_edges(*vi, g); inItr != inEnd; ++inItr)
              {
                const Vertex p = source(*inItr, g);

                std::set<Vertex> tempSet;
                std::set_intersection(T.begin(), T.end(),
                                      get(domMap, p).begin(),
                                      get(domMap, p).end(),
                                      std::inserter(tempSet, tempSet.begin()));
                T.swap(tempSet);
              }

            T.insert(*vi);
            if (T != get(domMap, *vi))
              {
                change = true;
                get(domMap, *vi).swap(T);
              }
          } // end of for (boost::tie(vi, viend) = vertices(g)
      } // end of while(change)

    // 2. Build dominator tree
    for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
      get(domMap, *vi).erase(*vi);

    Graph domTree(numOfVertices);

    for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
      {
        if (*vi == entry) continue;

        // We have to iterate through copied dominator set
        const std::set<Vertex> tempSet(get(domMap, *vi));
        typename std::set<Vertex>::const_iterator s;
        for (s = tempSet.begin(); s != tempSet.end(); ++s)
          {
            typename std::set<Vertex>::iterator t;
            for (t = get(domMap, *vi).begin(); t != get(domMap, *vi).end(); )
              {
        typename std::set<Vertex>::iterator old_t = t;
        ++t; // Done early because t may become invalid
                if (*old_t == *s) continue;
                if (get(domMap, *s).find(*old_t) != get(domMap, *s).end())
                  get(domMap, *vi).erase(old_t);
              }
          }
      }

    for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi)
      {
        if (*vi != entry && get(domMap, *vi).size() == 1)
          {
            Vertex temp = *get(domMap, *vi).begin();
            put(domTreePredMap, *vi, temp);
          }
      }
  }

  template<class Graph, class DomTreePredMap>
  void
  iterative_bit_vector_dominator_tree
    (const Graph& g,
     const typename graph_traits<Graph>::vertex_descriptor& entry,
     DomTreePredMap domTreePredMap)
  {
    typename property_map<Graph, vertex_index_t>::const_type
      indexMap = get(vertex_index, g);

    iterative_bit_vector_dominator_tree(g, entry, indexMap, domTreePredMap);
  }
} // namespace boost

#endif // BOOST_GRAPH_DOMINATOR_HPP


//
//=======================================================================
// Copyright 2012 Fernando Vilas
//           2010 Daniel Trebbien
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
//

// The maximum adjacency search algorithm was originally part of the
// Stoer-Wagner min cut implementation by Daniel Trebbien. It has been
// broken out into its own file to be a public search algorithm, with
// visitor concepts.
#ifndef BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H
#define BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H

/**
 * This is an implementation of the maximum adjacency search on an
 * undirected graph. It allows a visitor object to perform some
 * operation on each vertex as that vertex is visited.
 *
 * The algorithm runs as follows:
 *
 * Initialize all nodes to be unvisited (reach count = 0)
 *   and call vis.initialize_vertex
 * For i = number of nodes in graph downto 1
 *   Select the unvisited node with the highest reach count
 *     The user provides the starting node to break the first tie,
 *     but future ties are broken arbitrarily
 *   Visit the node by calling vis.start_vertex
 *   Increment the reach count for all unvisited neighbors
 *     and call vis.examine_edge for each of these edges
 *   Mark the node as visited and call vis.finish_vertex
 *
 */

#include <boost/concept_check.hpp>
#include <boost/concept/assert.hpp>
#include <boost/graph/buffer_concepts.hpp>
#include <boost/graph/exception.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/tuple/tuple.hpp>

#include <set>

namespace boost {
  template <class Visitor, class Graph>
  struct MASVisitorConcept {
    void constraints() {
      boost::function_requires< boost::CopyConstructibleConcept<Visitor> >();
      vis.initialize_vertex(u, g);
      vis.start_vertex(u, g);
      vis.examine_edge(e, g);
      vis.finish_vertex(u, g);
    }
    Visitor vis;
    Graph g;
    typename boost::graph_traits<Graph>::vertex_descriptor u;
    typename boost::graph_traits<Graph>::edge_descriptor e;
  };

  template <class Visitors = null_visitor>
  class mas_visitor {
  public:
    mas_visitor() { }
    mas_visitor(Visitors vis) : m_vis(vis) { }

    template <class Vertex, class Graph>
    void
    initialize_vertex(Vertex u, Graph& g)
    {
      invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
    }

    template <class Vertex, class Graph>
    void
    start_vertex(Vertex u, Graph& g)
    {
      invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
    }

    template <class Edge, class Graph>
    void
    examine_edge(Edge e, Graph& g)
    {
      invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
    }

    template <class Vertex, class Graph>
    void
    finish_vertex(Vertex u, Graph& g)
    {
      invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
    }

    BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,mas)
    BOOST_GRAPH_EVENT_STUB(on_start_vertex,mas)
    BOOST_GRAPH_EVENT_STUB(on_examine_edge,mas)
    BOOST_GRAPH_EVENT_STUB(on_finish_vertex,mas)

  protected:
    Visitors m_vis;
  };
  template <class Visitors>
  mas_visitor<Visitors>
  make_mas_visitor(Visitors vis) {
    return mas_visitor<Visitors>(vis);
  }
  typedef mas_visitor<> default_mas_visitor;

  namespace detail {
    template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
      void
      maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
      typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
      typedef typename boost::property_traits<WeightMap>::value_type weight_type;

     std::set<vertex_descriptor> assignedVertices;

     // initialize `assignments` (all vertices are initially
     // assigned to themselves)
     BGL_FORALL_VERTICES_T(v, g, Graph) {
       put(assignments, v, v);
     }

      typename KeyedUpdatablePriorityQueue::key_map keys = pq.keys();

      // set number of visited neighbors for all vertices to 0
      BGL_FORALL_VERTICES_T(v, g, Graph) {
        if (v == get(assignments, v)) { // foreach u \in V do
          put(keys, v, weight_type(0));          vis.initialize_vertex(v, g);

          pq.push(v);
        }
      }
      BOOST_ASSERT(pq.size() >= 2);

      // Give the starting vertex high priority
      put(keys, start, get(keys, start) + num_vertices(g) + 1);
      pq.update(start);

      // start traversing the graph
      //vertex_descriptor s, t;
      weight_type w;
      while (!pq.empty()) { // while PQ \neq {} do
        const vertex_descriptor u = pq.top(); // u = extractmax(PQ)
        w = get(keys, u);                        vis.start_vertex(u, g);
        pq.pop();                  //            vis.start_vertex(u, g);

        BGL_FORALL_OUTEDGES_T(u, e, g, Graph) { // foreach (u, v) \in E do
                                                 vis.examine_edge(e, g);

          const vertex_descriptor v = get(assignments, target(e, g));

          if (pq.contains(v)) { // if v \in PQ then
            put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
            pq.update(v);
          }
        }

        typename std::set<vertex_descriptor>::const_iterator assignedVertexIt, assignedVertexEnd = assignedVertices.end();
        for (assignedVertexIt = assignedVertices.begin(); assignedVertexIt != assignedVertexEnd; ++assignedVertexIt) {
          const vertex_descriptor uPrime = *assignedVertexIt;

          if (get(assignments, uPrime) == u) {
            BGL_FORALL_OUTEDGES_T(uPrime, e, g, Graph) { // foreach (u, v) \in E do
                                                 vis.examine_edge(e, g);

              const vertex_descriptor v = get(assignments, target(e, g));

              if (pq.contains(v)) { // if v \in PQ then
                put(keys, v, get(keys, v) + get(weights, e)); // increasekey(PQ, v, wA(v) + w(u, v))
                pq.update(v);
              }
            }
          }
        }
                                                 vis.finish_vertex(u, g);
      }
    }
  } // end namespace detail

  template <class Graph, class WeightMap, class MASVisitor, class VertexAssignmentMap, class KeyedUpdatablePriorityQueue>
    void
maximum_adjacency_search(const Graph& g, WeightMap weights, MASVisitor vis, const typename boost::graph_traits<Graph>::vertex_descriptor start, VertexAssignmentMap assignments, KeyedUpdatablePriorityQueue pq) {
    BOOST_CONCEPT_ASSERT((boost::IncidenceGraphConcept<Graph>));
    BOOST_CONCEPT_ASSERT((boost::VertexListGraphConcept<Graph>));
    typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename boost::graph_traits<Graph>::vertices_size_type vertices_size_type;
    typedef typename boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
    BOOST_CONCEPT_ASSERT((boost::Convertible<typename boost::graph_traits<Graph>::directed_category, boost::undirected_tag>));
    BOOST_CONCEPT_ASSERT((boost::ReadablePropertyMapConcept<WeightMap, edge_descriptor>));
    // typedef typename boost::property_traits<WeightMap>::value_type weight_type;
    boost::function_requires< MASVisitorConcept<MASVisitor, Graph> >();
    BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<VertexAssignmentMap, vertex_descriptor>));
    BOOST_CONCEPT_ASSERT((boost::Convertible<vertex_descriptor, typename boost::property_traits<VertexAssignmentMap>::value_type>));
    BOOST_CONCEPT_ASSERT((boost::KeyedUpdatableQueueConcept<KeyedUpdatablePriorityQueue>));

    vertices_size_type n = num_vertices(g);
    if (n < 2)
      throw boost::bad_graph("the input graph must have at least two vertices.");
    else if (!pq.empty())
      throw std::invalid_argument("the max-priority queue must be empty initially.");

    detail::maximum_adjacency_search(g, weights,
                                            vis, start,
                                            assignments, pq);
  }

  namespace graph {
    namespace detail {
      template <typename WeightMap>
      struct mas_dispatch {
        typedef void result_type;
        template <typename Graph, typename ArgPack>
        static result_type apply(const Graph& g,
                          //const bgl_named_params<P,T,R>& params,
                          const ArgPack& params,
                          WeightMap w) {

          using namespace boost::graph::keywords;
          typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
          typedef typename WeightMap::value_type weight_type;

          typedef boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > default_pq_gen_type;

          default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)));

          typename boost::result_of<default_pq_gen_type(const Graph&, const ArgPack&)>::type pq = pq_gen(g, params);

          boost::maximum_adjacency_search
               (g,
                w,
                params [ _visitor | make_mas_visitor(null_visitor())],
                params [ _root_vertex | *vertices(g).first],
                params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, params)],
                pq
                );
        }
      };

      template <>
      struct mas_dispatch<boost::param_not_found> {
        typedef void result_type;

        template <typename Graph, typename ArgPack>
        static result_type apply(const Graph& g,
                          const ArgPack& params,
                          param_not_found) {

          using namespace boost::graph::keywords;
          typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;

          // get edge_weight_t as the weight type
          typedef typename boost::property_map<Graph, edge_weight_t> WeightMap;
          typedef typename WeightMap::value_type weight_type;

          typedef boost::detail::make_priority_queue_from_arg_pack_gen<boost::graph::keywords::tag::max_priority_queue, weight_type, vertex_descriptor, std::greater<weight_type> > default_pq_gen_type;

          default_pq_gen_type pq_gen(choose_param(get_param(params, boost::distance_zero_t()), weight_type(0)));

          typename boost::result_of<default_pq_gen_type(const Graph&, const ArgPack&)>::type pq = pq_gen(g, params);

          boost::maximum_adjacency_search
               (g,
                get(edge_weight, g),
                params [ _visitor | make_mas_visitor(null_visitor())],
                params [ _root_vertex | *vertices(g).first],
                params [ _vertex_assignment_map | boost::detail::make_property_map_from_arg_pack_gen<boost::graph::keywords::tag::vertex_assignment_map, vertex_descriptor>(vertex_descriptor())(g, params)],
                pq
                );
        }
      };
    } // end namespace detail
  } // end namespace graph

  // Named parameter interface
  //BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(maximum_adjacency_search, 1)
  template <typename Graph, typename P, typename T, typename R>
  void
  maximum_adjacency_search (const Graph& g,
      const bgl_named_params<P,T,R>& params) {

    typedef bgl_named_params<P, T, R> params_type;
    BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)

    // do the dispatch based on WeightMap
    typedef typename get_param_type<edge_weight_t, bgl_named_params<P,T,R> >::type W;
    graph::detail::mas_dispatch<W>::apply(g, arg_pack, get_param(params, edge_weight));
  }

  namespace graph {
    namespace detail {
      template <typename Graph>
      struct maximum_adjacency_search_impl {
        typedef void result_type;

        template <typename ArgPack>
        void
        operator() (const Graph& g, const ArgPack& arg_pack) const {
          // call the function that does the dispatching
          typedef typename get_param_type<edge_weight_t, ArgPack >::type W;
          graph::detail::mas_dispatch<W>::apply(g, arg_pack, get_param(arg_pack, edge_weight));
        }
      };
    } // end namespace detail
    BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(maximum_adjacency_search,1,5)
  } // end namespace graph

} // end namespace boost

#include <boost/graph/iteration_macros_undef.hpp>

#endif // BOOST_GRAPH_MAXIMUM_ADJACENCY_SEARCH_H


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*  This file is part of the library KASKADE 7                               */
/*    see http://www.zib.de/projects/kaskade7-finite-element-toolbox         */
/*                                                                           */
/*  Copyright (C) 2015-2015 Zuse Institute Berlin                            */
/*                                                                           */
/*  KASKADE 7 is distributed under the terms of the ZIB Academic License.    */
/*    see $KASKADE/academic.txt                                              */
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef VTKWRITER_HH
#define VTKWRITER_HH

#include <algorithm>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <type_traits>
#include <vector>

#include <boost/fusion/include/zip.hpp>
#include <boost/range/iterator_range.hpp>

#include <dune/grid/common/grid.hh>
#include <dune/geometry/referenceelements.hh>

#include "io/iobase.hh"
#include "utilities/detailed_exception.hh"
#undef min

namespace Kaskade
{
  /**
   * \cond internals
   */

  namespace FunctionSpace_Detail {
    // forward declaration
    template <class> class ToDomainRepresentation;
  }

  namespace VTKWriterDetail
  {
    // returns the textual VTK notation of this system's endianness.
    std::string vtkEndianness();

    enum VTKGeometryType
    {
      vtkLine = 3,
      vtkTriangle = 5,
      vtkQuadrilateral = 9,
      vtkTetrahedron = 10,
      vtkHexahedron = 12,
      vtkPrism = 13,
      vtkPyramid = 14,
      vtkquadLine = 21,
      vtkquadTriangle = 22,
      vtkquadQuadrilateral = 23,
      vtkquadTetrahedron = 24,
      vtkquadHexahedron = 25,
    };

    //! mapping from GeometryType to VTKGeometryType
    VTKGeometryType vtkType(Dune::GeometryType const& t, int order);

    /**
     * \brief Returns the subentity number and codimension for any VTK point in a cell.
     */
    std::pair<int,int> vtkPointToDune(Dune::GeometryType const& type, int vtkPoint);

    // forward declaration
    class Base64Writer;

    //! base class for VTK data array writers
    // T  is a scalar type (float,double,int,...)
    template <class T>
    class VTKDataArrayWriter
    {
    public:
    /**
     * @brief Constructor.
     *
     * @param s           The stream to write to
     * @param outputType  ASCII or binary
     * @param name        The name of the vtk array
     * \param ncomps      number of vectorial components (1 or 3)
     * @param entries     the number of data entries to write
     */
      VTKDataArrayWriter(std::ostream &s, IoOptions::OutputType outputType, std::string const& name, int ncomps,
                         size_t entries, int indentCount, int precision);

      //! write one data element
      template <int m>
      void write (Dune::FieldVector<T,m> const&);

      void write(T);

      //!  destructor
      ~VTKDataArrayWriter();

    private:
      std::ostream& s;
      IoOptions::OutputType outputType;
      int ncomps;
      int counter;
      int numPerLine;
      int indentCount;
      int precision;
      std::unique_ptr<Base64Writer> base64;
    };

    // ---------------------------------------------------------------------------

    //! write indentation to stream
    void indent(std::ostream& s, int indentCount);

    /// This gathers some information about the grid and supports the output of the grid
    template <class GridView>
    struct VTKGridInfo
    {
      using Cell         = typename GridView::template Codim<0>::Entity;
      using IndexSet     = typename GridView::IndexSet;
      using CellIterator = typename GridView::template Codim<0>::Iterator;

      static int constexpr dim = GridView::dimension;

      VTKGridInfo(GridView const& gridView_, IoOptions const& options_)
      : gridView(gridView_),
        cells(gridView.template begin<0>(),gridView.template end<0>()),
        ncells(gridView.size(0)),
        options(options_)
      {
        // For counting the corners (i.e. all corners of all cells) we step through the
        // cells and count their respective corners (and edges for order two). This is
        // general enough to treat mixed grids containing different cell types.
        ncorners = 0;
        for (auto const& cell: cells)
        {
          ncorners += cell.subEntities(dim);
          if (options.order==2)
            ncorners += cell.subEntities(dim-1);
        }

        // In conforming mode, the number of points is just the number of vertices
        // (plus edges for oder two). Otherwise, points and corners coincide.
        if (options.dataMode==IoOptions::conforming)
        {
          npoints = gridView.size(dim);
          if (options.order==2)
            npoints += gridView.size(dim-1);
        }
        else
          npoints = ncorners;
      }

      // returns entity center coordinates
      template <class Cell>
      auto center(Cell const& cell, int subindex, int codim) const
      {
        return Dune::ReferenceElements<typename GridView::ctype,dim>::general(cell.type()).position(subindex,codim);
      }

      // returns a globally unique index for vertices and edges in conforming mode.
      // Vertices come first, then edges.
      template <class Cell>
      int conformingIndex(Cell const& cell, int subindex, int codim) const
      {
        // due to the sorting vertices first then edges there is no need to switch between order 1 and 2
        if (codim==dim)
          return gridView.indexSet().subIndex(cell,subindex,codim);
        else
          return gridView.size(dim) + gridView.indexSet().subIndex(cell,subindex,codim);
      }

      // Writes the point coordinates to the VTK XML stream
      void writeGridPoints (int indentCount, std::ostream& s) const
      {
        VTKDataArrayWriter<typename GridView::ctype> p(s, options.outputType, "Coordinates", 3, npoints, indentCount, options.precision);

        if (options.dataMode==IoOptions::conforming)
        {
          std::vector<Dune::FieldVector<typename GridView::ctype,GridView::dimensionworld>> xs(npoints);
          for (auto const& cell: cells)
          {
            for (int corner=0; corner<cell.subEntities(dim); ++corner)   // global coordinates of all corners
              xs[conformingIndex(cell,corner,dim)] = cell.geometry().corner(corner);

            if (options.order == 2)
              for (int edge=0; edge<cell.subEntities(dim-1); ++edge)     // global coordinates of all edges
                xs[conformingIndex(cell,edge,dim-1)] = cell.geometry().global(center(cell,edge,dim-1));
          }

          for (auto const& x: xs)
            p.write(x);
        }
        else // nonconforming
        {
          for (auto const& cell: cells)
          {
            for (int corner=0; corner<cell.subEntities(dim); ++corner)
              p.write(cell.geometry().corner(corner));

            if (options.order == 2)
              for (int edge=0; edge<cell.subEntities(dim-1); ++edge)
                p.write(cell.geometry().global(center(cell,edge,dim-1)));
          }
        }
      }

      void writeGridCells (int indentCount, std::ostream& s) const
      {
        // connectivity
        auto p1 = std::make_unique<VTKDataArrayWriter<int>>(s, options.outputType, "connectivity", 1, ncorners, indentCount, options.precision);

        int offset = 0;
        std::vector<int> offsets; offsets.reserve(ncells);
        for (auto const& cell: cells)                                             // step through all cells
        {
          int const numCorners = cell.subEntities(dim);
          int const numEdges = cell.subEntities(dim-1);
          int const numPoints = numCorners + (options.order==2? numEdges: 0);

          for (int vtkPoint=0; vtkPoint<numPoints; ++vtkPoint)                   // visit each point in that cell
          {
            auto subentity = vtkPointToDune(cell.type(),vtkPoint);               // and find its Dune coordinates
            p1->write( options.dataMode==IoOptions::conforming?
                          conformingIndex(cell,subentity.first,subentity.second):
                          offset + (subentity.second==dim? 0: numCorners) + subentity.first );
          }
          offset += numPoints;                                                   // in nonconforming mode, the points are stored blockwise,
          offsets.push_back(offset);
        }                                                                        // cell by cell, just advance the offset
        p1.reset(); // write end tag on destruction

        // write offsets
        auto p2 = std::make_unique<VTKDataArrayWriter<int>>(s, options.outputType, "offsets", 1, ncells, indentCount, options.precision);
        for (int off: offsets)
          p2->write(off);
        p2.reset(); // write end tag on destruction

        // types only if dimension greater than 1 - there is only one 1D cell type: line
        if (dim>1)
        {
          VTKDataArrayWriter<unsigned char> p(s, options.outputType, "types", 1, ncells, indentCount, options.precision);
          for (auto const& cell: cells)
            p.write(static_cast<unsigned char>(vtkType(cell.type(),options.order)));
        }
      }

      GridView const& gridView;
      boost::iterator_range<CellIterator> cells;
      size_t ncorners;
      size_t npoints;
      size_t ncells;
      IoOptions const& options;
    };

    // ----------------------------------------------------------------------------------------

    template <class GridView, class Function, class Names>
    void writeCellData (VTKGridInfo<GridView> const& gridInfo, Function const& pair, Names const& names, int indentCount, std::ostream& s)
    {
      auto const& f = boost::fusion::at_c<0>(pair);

      // Check whether this is best represented as cell data: only if it is (piecewise) constant.
      if (f.space().mapper().maxOrder() > 0)
        return;

      auto varDesc = boost::fusion::at_c<1>(pair);
      VTKDataArrayWriter<double> p(s, gridInfo.options.outputType, names[varDesc.id], varDesc.m, gridInfo.ncells, indentCount, gridInfo.options.precision);
      for (auto const& cell: gridInfo.cells)
        p.write(f.value(cell,gridInfo.center(cell,0,0)));
    }

    template <class GridView, class Function, class Names>
    void writeVertexData (VTKGridInfo<GridView> const& gridInfo, Function const& pair, Names const& names, int indentCount, std::ostream& s)
    {
      auto const& f = boost::fusion::at_c<0>(pair);
      using ValueType = typename std::remove_reference_t<typename boost::fusion::result_of::value_at_c<Function,0>::type>::ValueType;
      constexpr int dim = GridView::dimension;

     // Check whether this is best represented as vertex data: only if it is not (piecewise) constant.
      if (f.space().mapper().maxOrder() == 0)
        return;

      auto varDesc = boost::fusion::at_c<1>(pair);
      VTKDataArrayWriter<double> p(s, gridInfo.options.outputType, names[varDesc.id], varDesc.m, gridInfo.npoints, indentCount, gridInfo.options.precision);

      if (gridInfo.options.dataMode==Kaskade::IoOptions::conforming)
      {
        std::vector<ValueType> fs(gridInfo.npoints,ValueType(0.0));   // function values, in conforming mode average over multiple points
        std::vector<short> count(gridInfo.npoints,0);                  // count how many points contribute to an entity

        // TODO: Currently boundary FE functions are zero on cells which only touch the boundary by one vertex (or edge in 3D). This will lead to unwanted results when values are averaged.
        // Therefore, we use the following two lines to transform boundary FE functions to continuous FE functions over the whole domain, then averaging works as expected.
        // Remove this when not necessary any longer. (And also delete ToDomainRepresetation from functionspace.hh)
        FunctionSpace_Detail::ToDomainRepresentation<std::remove_const_t<std::remove_reference_t<typename boost::fusion::result_of::value_at_c<Function,0>::type>>> tdr(f);
        auto const& df = tdr.get();

        for (auto const& cell: gridInfo.cells)
        {
          int const numPoints = cell.subEntities(dim) + (gridInfo.options.order==2? cell.subEntities(dim-1): 0);
          for (int point=0; point<numPoints; ++point)
          {
            auto subentity = vtkPointToDune(cell.type(),point);
            auto xi = gridInfo.center(cell,subentity.first,subentity.second);          // local coordinate of point in current cell
            int idx = gridInfo.conformingIndex(cell,subentity.first,subentity.second); // global index of point
            ++count[idx];
            fs[idx] += df.value(cell,xi);
          }
        }

        for (int i=0; i<gridInfo.npoints; ++i)          // now write out the values in vertex order
          p.write(fs[i]/static_cast<double>(count[i])); // and average them on writing
      }
      else // nonconforming
      {
        for (auto const& cell: gridInfo.cells)
        {
          // First write corner values
          for (int corner=0; corner<cell.subEntities(dim); ++corner)
            p.write(f.value(cell,gridInfo.center(cell,corner,dim)));

          // If required, write edge midpoint values as well.
          if (gridInfo.options.order==2)
            for (int edge=0; edge<cell.subEntities(dim-1); ++edge)
              p.write(f.value(cell,gridInfo.center(cell,edge,dim-1)));
        }
      }
    }

    // The following piece of code defines the "active" scalar and vectorial variables (those used to immediately color the output in Paraview).
    // According to VTK file formats, there need not be any active scalar or vectorial variable. Taking simply the first one as is done here makes little sense.
    // TODO: make this configurable via IoOptions.
    template <class Functions, class Names>
    std::string guessActiveFields(Functions const& functions, Names const& names, bool cellData)
    {
      std::string scalar = "";
      std::string vector = "";

      boost::fusion::for_each(functions,[&](auto const& pair)
      {
        auto const& f = boost::fusion::at_c<0>(pair);
        auto varDesc = boost::fusion::at_c<1>(pair);

        // Check whether this is best represented as cell or point data.
        if ( (f.space().mapper().maxOrder()==0 && cellData)
          || (f.space().mapper().maxOrder()>0 && !cellData) )
        {
          if (f.components>1 && vector.empty())
            vector = " Vectors=\"" + names[varDesc.id] + "\"";
          if (f.components==1 && scalar.empty())
            scalar = " Scalars=\"" + names[varDesc.id] + "\"" ;
        }
      });
      return scalar+vector;
    }

  }
  /**
   * \endcond
   */

  // ---------------------------------------------------------------------------------------------

  /**
   * \ingroup IO
   * \brief Writes a set of finite element functions in VTK XML format to a stream.
   * \param vars a set of finite element functions to write
   * \param options specifies how the data shall be written
   * \param s the output stream
   */
  template <class VariableSet>
  void writeVTK(VariableSet const& vars, IoOptions options, std::ostream& s)
  {
    using namespace VTKWriterDetail;
    options.order = std::max(1,std::min(options.order,2));

    // If data mode "inferred" is requested, try to select either conforming or nonconforming
    // based on rules.

    int indentCount = 0;
    constexpr int dim = VariableSet::Descriptions::Grid::dimension;

    VTKGridInfo<typename VariableSet::Descriptions::GridView> gridInfo(vars.descriptions.gridView,options);

    // xml header
    s << "<?xml version=\"1.0\"?>" << std::endl;

    // VTKFile
    std::string const gridTag = dim>1? "UnstructuredGrid": "PolyData";
    s << "<VTKFile type=\"" << gridTag << "\" version=\"0.1\" byte_order=\"" << vtkEndianness() << "\">" << std::endl;
    ++indentCount;

    // UnstructuredGrid
    indent(s,indentCount);
    s << "<" << gridTag << ">" << std::endl;
    ++indentCount;

    // Piece
    indent(s,indentCount);
    if (dim>1)
      s << "<Piece NumberOfPoints=\"" << gridInfo.npoints << "\" NumberOfCells=\"" << gridInfo.ncells << "\">" << std::endl;
    else
      s << "<Piece NumberOfPoints=\"" << gridInfo.npoints << "\" NumberOfVerts=\"0\" NumberOfLines=\"" << gridInfo.ncells << "\" NumberOfPolys=\"0\">" << std::endl;
    ++indentCount;

    // Write grid points
    indent(s,indentCount); s << "<Points>" << std::endl;
    gridInfo.writeGridPoints(indentCount+1,s);
    indent(s,indentCount); s << "</Points>" << std::endl;

    // Write grid cells
    std::string const cellTagName = dim>1? "Cells": "Lines";
    indent(s,indentCount);  s << '<' << cellTagName << '>' << std::endl;
    gridInfo.writeGridCells(indentCount+1,s);
    indent(s,indentCount); s << "</" << cellTagName << '>' << std::endl;

    // associate the FE functions with their variable descriptions
    auto varDesc = typename VariableSet::Descriptions::Variables();
    auto functions = boost::fusion::zip(vars.data,varDesc);

    indent(s,indentCount); s << "<CellData" << guessActiveFields(functions,vars.descriptions.names,true) << ">" << std::endl;
    boost::fusion::for_each(functions,[&](auto const& f) { writeCellData(gridInfo,f,vars.descriptions.names,indentCount+1,s); });
    indent(s,indentCount); s << "</CellData>" << std::endl;

    indent(s,indentCount); s << "<PointData" << guessActiveFields(functions,vars.descriptions.names,false) << ">" << std::endl;
    boost::fusion::for_each(functions,[&](auto const& f) { writeVertexData(gridInfo,f,vars.descriptions.names,indentCount+1,s); });
    indent(s,indentCount); s << "</PointData>" << std::endl;

    // /Piece
    --indentCount;
    indent(s,indentCount); s << "</Piece>" << std::endl;

    // /UnstructuredGrid
    --indentCount;
    indent(s,indentCount); s << "</" << gridTag << ">" << std::endl;

    // /VTKFile
    s << "</VTKFile>" << std::endl;
  }

  /**
   * \ingroup IO
   * \brief Writes a set of finite element functions in VTK XML format to a stream.
   * \param vars a set of finite element functions
   * \param name file name (without trailing .vtu)
   *
   * Note that Paraview can create a time line implicitly from numbered files. use paddedString for easy creation
   * of numbered file names.
   */
  template <class VariableSet>
  void writeVTK(VariableSet const& vars, std::string name, IoOptions const& options)
  {
    // generate filename for process data
    name += (VariableSet::Descriptions::GridView::dimension>1? ".vtu" : ".vtp");

    // write process data
    std::ofstream file(name);
    if (!file)
      throw Kaskade::FileIOException("Opening  failed.\n",name,__FILE__,__LINE__);
    writeVTK(vars,options,file);
    if (!file)
      throw Kaskade::FileIOException("Writing  failed.\n",name,__FILE__,__LINE__);
    file.close();
  }

}

// --------------------------------------------------------------------------------------------

#endif