/*
 * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
 * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
 * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
 * Copyright 2015 Janosch Nikolic, ASL, ETH Zurich, Switzerland
 * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
 * Copyright 2016 Geoffrey Hunter <gbmhunter@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef COMMON_H
#define COMMON_H

#include <Eigen/Dense>
#include <gazebo/gazebo.hh>

namespace gazebo
{

//===============================================================================================//
//========================================= DEBUGGING ===========================================//
//===============================================================================================//

/// \addtogroup Debug Print Switches
/// @{

// The following boolean constants enable/disable debug printing when certain plugin methods are called.
// Suitable for debugging purposes. Left on permanently can swamp std::out and can crash Gazebo.

  static const bool kPrintOnPluginLoad = false;
  static const bool kPrintOnUpdates = false;
  static const bool kPrintOnMsgCallback = false;

/// @}

// Default values
  static const std::string kDefaultNamespace = "";
  static constexpr double kDefaultRotorVelocitySlowdownSim = 10.0;

//===============================================================================================//
//================================== TOPICS FOR ROS INTERFACE ===================================//
//===============================================================================================//

// These should perhaps be defined in an .sdf/.xacro file instead?
  static const std::string kConnectGazeboToRosSubtopic = "connect_gazebo_to_ros_subtopic";
  static const std::string kConnectRosToGazeboSubtopic = "connect_ros_to_gazebo_subtopic";

/// \brief    Special-case topic for ROS interface plugin to listen to (if present)
///           and broadcast transforms to the ROS system.
  static const std::string kBroadcastTransformSubtopic = "broadcast_transform";

/// \brief      Obtains a parameter from sdf.
/// \param[in]  sdf           Pointer to the sdf object.
/// \param[in]  name          Name of the parameter.
/// \param[out] param         Param Variable to write the parameter to.
/// \param[in]  default_value Default value, if the parameter not available.
/// \param[in]  verbose       If true, gzerror if the parameter is not available.
  template<class T>
  bool getSdfParam(
    sdf::ElementPtr sdf, const std::string & name, T & param, const T & default_value, const bool & verbose =
    false)
  {
    if (sdf->HasElement(name)) {
      param = sdf->GetElement(name)->Get<T>();
      return true;
    } else {
      param = default_value;
      if (verbose) {
        gzerr << "[rotors_gazebo_plugins] Please specify a value for parameter \"" << name <<
          "\".\n";
      }
    }
    return false;
  }

}

/// \brief    This class can be used to apply a first order filter on a signal.
///           It allows different acceleration and deceleration time constants.
/// \details
///           Short reveiw of discrete time implementation of first order system:
///           Laplace:
///             X(s)/U(s) = 1/(tau*s + 1)
///           continous time system:
///             dx(t) = (-1/tau)*x(t) + (1/tau)*u(t)
///           discretized system (ZoH):
///             x(k+1) = exp(samplingTime*(-1/tau))*x(k) + (1 - exp(samplingTime*(-1/tau))) * u(k)
template<typename T>
class FirstOrderFilter
{

public:
  FirstOrderFilter(double timeConstantUp, double timeConstantDown, T initialState)
  : timeConstantUp_(timeConstantUp),
    timeConstantDown_(timeConstantDown),
    previousState_(initialState) {}

  /// \brief    This method will apply a first order filter on the inputState.
  T updateFilter(T inputState, double samplingTime)
  {

    T outputState;
    if (inputState > previousState_) {
      // Calcuate the outputState if accelerating.
      double alphaUp = exp(-samplingTime / timeConstantUp_);
      // x(k+1) = Ad*x(k) + Bd*u(k)
      outputState = alphaUp * previousState_ + (1 - alphaUp) * inputState;

    } else {
      // Calculate the outputState if decelerating.
      double alphaDown = exp(-samplingTime / timeConstantDown_);
      outputState = alphaDown * previousState_ + (1 - alphaDown) * inputState;
    }
    previousState_ = outputState;
    return outputState;

  }

  ~FirstOrderFilter() {}

protected:
  double timeConstantUp_;
  double timeConstantDown_;
  T previousState_;
};

/// \brief    Computes a quaternion from the 3-element small angle approximation theta.
template<class Derived>
Eigen::Quaternion<typename Derived::Scalar> QuaternionFromSmallAngle(
  const Eigen::MatrixBase<Derived> & theta)
{
  typedef typename Derived::Scalar Scalar;
  EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived);
  EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived, 3);
  const Scalar q_squared = theta.squaredNorm() / 4.0;

  if (q_squared < 1) {
    return Eigen::Quaternion<Scalar>(
      sqrt(
        1 - q_squared), theta[0] * 0.5, theta[1] * 0.5, theta[2] * 0.5);
  } else {
    const Scalar w = 1.0 / sqrt(1 + q_squared);
    const Scalar f = w * 0.5;
    return Eigen::Quaternion<Scalar>(w, theta[0] * f, theta[1] * f, theta[2] * f);
  }
}

template<class In, class Out>
void copyPosition(const In & in, Out * out)
{
  out->x = in.x;
  out->y = in.y;
  out->z = in.z;
}

#endif /* ROTORS_GAZEBO_PLUGINS_COMMON_H_ */


/**
 @file tile.hpp
 @author pat <pat@fourthbox.com>
 */

#ifndef LIBPMG_UTILS_HPP_
#define LIBPMG_UTILS_HPP_

#include <queue>
#include <unordered_map>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "map.hpp"

namespace libpmg {

/**
 Simple implementation of a priority queue.
 */
template<typename T, typename priority_t>
struct PriorityQueue {
    typedef std::pair<priority_t, T> PQElement;
    std::priority_queue<PQElement, std::vector<PQElement>,
    std::greater<PQElement>> elements;

    inline bool empty() const { return elements.empty(); }

    inline void push(T item, priority_t priority) {
        elements.emplace(priority, item);
    }

    inline T pop() {
        T best_item = elements.top().second;
        elements.pop();
        return best_item;
    }

    inline std::size_t size() {
        if (elements.size() < std::numeric_limits<std::size_t>::max())
            return elements.size();

        return std::numeric_limits<std::size_t>::max();
    }
};

/**
 A struct containing utility functions
 */
struct Utils {

    /**
     Prints debug log informations.
     @param message The message to be printed
     */
    static inline void LogDebug(std::string const &message) {

        printf("%s\n", message.c_str());
    }

    /**
     Prints debug log informations.
     @param context A string indicating the context for better describing the message
     @param message The message to be printed
     */
    static inline void LogDebug(std::string const &context, std::string const &message) {

        printf("%s:: %s\n", context.c_str(), message.c_str());
    }

    /**
     Prints debug log informations with a warning sign.
     @param context A string indicating the context for better describing the message
     @param message The message to be printed
     */
    static inline void LogWarning(std::string const &context, std::string const &message) {

        printf("[WARNING] %s:: %s\n", context.c_str(), message.c_str());
    }

    /**
     Prints debug log informations with an error sign.
     @param context A string indicating the context for better describing the message
     @param message The message to be printed
     */
    static inline void LogError(std::string const &context, std::string const &message) {

        printf("[ERROR] %s:: %s\n", context.c_str(), message.c_str());
    }

    /**
     A function that uses the BFS algorithm to find the shortest path between 2 Location on a Map.
     @param start_coor A pair of coordinats representing the start location
     @param end_coor A pair of coordinats representing the end location
     @param map A pointer to the Map where the search is happening
     @param diagonals Whether diagonal paths should be used (compatible with FOUR_DIRECTIONAL, creating a "stair" effect)
     @param dir Whether locations can be connected diagonally
     @param reset_path_flags Whether path flags should be reset before running the algorithm
     @return A pointer to an unordered map of locations. The key is the location "connected" to the value on the generated path
     */
    static std::unique_ptr<std::unordered_map<Location*, Location*>>
    BreadthFirstSearch(std::pair<std::size_t, std::size_t> start_coor,
                       std::pair<std::size_t, std::size_t> end_coor,
                       Map *map,
                       bool diagonals,
                       MoveDirections const &dir,
                       bool reset_path_flags = true);

    /**
     A function that uses the Dijkstra algorithm to find the shortest path between 2 Location on a Map.
     @param start_coor A pair of coordinats representing the start location
     @param end_coor A pair of coordinats representing the end location
     @param map A pointer to the Map where the search is happening
     @param dir Whether locations can be connected diagonally
     @param reset_path_flags Whether path flags should be reset before running the algorithm
     @return A pointer to an unordered map of locations. The key is the location "connected" to the value on the generated path
     */
    static std::unique_ptr<std::unordered_map<Location*, Location*>>
    Dijkstra(std::pair<std::size_t, std::size_t> start_coor,
             std::pair<std::size_t, std::size_t> end_coor,
             Map *map,
             MoveDirections const &dir,
             bool reset_path_flags = true);

    /**
     A function that uses the Astar algorithm to find the shortest path between 2 Location on a Map.
     @param start_coor A pair of coordinats representing the start location
     @param end_coor A pair of coordinats representing the end location
     @param map A pointer to the Map where the search is happening
     @param dir Whether locations can be connected diagonally
     @param reset_path_flags Whether path flags should be reset before running the algorithm
     @return A pointer to an unordered map of locations. The key is the location "connected" to the value on the generated path
     */
    static std::unique_ptr<std::unordered_map<Location*, Location*>>
    Astar(std::pair<std::size_t, std::size_t> start_coor,
          std::pair<std::size_t, std::size_t> end_coor,
          Map *map,
          MoveDirections const &dir,
          bool reset_path_flags = true);

    /**
     Generates a random unique id.
     @return A string with a UUID
     */
    static std::string GenerateUUID() { return boost::uuids::to_string(boost::uuids::random_generator()()); }
};

}

#endif /* LIBPMG_UTILS_HPP_ */


/*
 * vi:ts=4:tw=78:shiftwidth=4:expandtab
 * vim600:fdm=marker
 *
 * gistrainer.cpp  -  a trainer for conditional ME model with GIS algorithm
 *
 * An implementation of Generalized Iterative Scaling.  The reference paper
 * for this implementation was Adwait Ratnaparkhi's tech report at the
 * University of Pennsylvania's Institute for Research in Cognitive Science,
 * and is available at ftp://ftp.cis.upenn.edu/pub/ircs/tr/97-08.ps.Z
 *
 * This C++ implementation is originally based on java maxent implementation,
 * with the help of developers from java maxent.
 * see http://maxent.sf.net
 *
 * Current implementation implements the "Correction Free" GIS algorithm with
 * Gaussian prior smoothing described in [Curran and Clark, 2003]:
 * "Investigating GIS and Smoothing for Maximum Entropy Taggers".
 *
 * Without the computation of correction parameter, the new GIS algorithm is
 * much faster, making the already simple algorithm simpler.
 *
 * Copyright (C) 2002 by Zhang Le <ejoy@users.sourceforge.net>
 * Begin       : 31-Dec-2002
 * Last Change : 08-Feb-2012.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <cassert>
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <tr1/unordered_map>
#include <boost/timer.hpp>
#include <idmlib/maxent/gistrainer.hpp>
#include <idmlib/maxent/display.hpp>
#include <idmlib/maxent/finite.h>

namespace maxent{

void GISTrainer::init_trainer() {
    assert(m_params->size() > 0);
    assert(m_es->size() > 0);

    // (bool) is needed for BCC5.5
    if ((bool)m_heldout_es && m_heldout_es->size() > 0) {
        cerr << "calculating heldout accuracy is not supported in GIS trainer yet." << endl;
    }

    m_modifiers.reset(new vector<vector<double> >
            (m_params->size(), vector<double>(0)) );
    m_observed_expects.reset(new vector<vector<double> >
            (m_params->size(), vector<double>(0)) );

    // init all thetas to 0.0
    for (size_t i = 0; i < m_params->size(); ++i) {
        std::vector<pair<size_t, size_t> >& param = (*m_params)[i];
        (*m_modifiers)[i].resize(param.size());
        (*m_observed_expects)[i].resize(param.size());
        for (size_t j = 0; j < param.size(); ++j) {
            m_theta[param[j].second] = 0.0;
            assert((*m_modifiers)[i][j] == 0.0);
        }
    }

    // determine the correction constant
    // C = max sum_{x,y} f_i(x, y)
    // m_correct_constant = (*m_es)[0].context_size();
    m_correct_constant = -999;
    for (size_t i = 0; i < m_es->size(); ++i) {
        // size_t len = (*m_es)[i].context_size();
        double t = 0.0;
        Event& e = (*m_es)[i];
        // assume no duplicated features
        for (size_t j = 0; j < e.context_size(); ++j) {
            assert (e.m_context[j].second >= 0.0);
            t += e.m_context[j].second;
        }

        if (t > m_correct_constant)
            m_correct_constant = t;
    }

    m_N = 0;
    for (vector<Event>::iterator it = m_es->begin();
            it != m_es->end(); ++it) {
        // XXX: is the calculation of active features correct?
        m_N += it->m_count;
    }

    // calculate observed feature expectations
    // a hash map to hold the value of feature <pred,outcome> pair occured in event list
    // which is the sum of active feature f_i(a,b) in the training set
    typedef std::tr1::unordered_map <pair<size_t, size_t>, float, featid_hasher> FeatSumMap;
    FeatSumMap feat_sum;
    for (vector<Event>::const_iterator it = m_es->begin();
            it != m_es->end(); ++it) {
        size_t len = it->context_size();
        for (size_t i = 0; i < len; ++i) {
        // check for feature values, current implementation only supports
        // binary features
//            if (it->m_context[i].second != 1.0)
//                throw runtime_error("Current GIS implementation only supports binary features, use L-BFGS instead");
            feat_sum[make_pair(it->m_context[i].first,it->m_outcome)] +=
                (it->m_count * it->m_context[i].second);
        }
    }

    // Get the observed expectations of the features. Strictly speaking,
    // we should divide the counts by the number of tokens, but because of
    // the way the model's expectations are approximated in the
    // implementation, this is cancelled out when we compute the next
    // iteration of a parameter, making the extra divisions wasteful.
    // Because we need no division of N in Ep<f_i> and Eq<f_i>
    // when calculating delta of update paramater:
    // lambda(n+1) = lambda(n) + (1/C)*[log(Ep<f_i>) - log(Eq<f_i>)]

    FeatSumMap::iterator it;
    for (size_t pid = 0; pid < m_params->size(); ++pid) {
        vector<pair<size_t, size_t> >& param = (*m_params)[pid];
        vector<double>& observ = (*m_observed_expects)[pid];
        for (size_t j = 0; j < param.size(); ++j) {
            it = feat_sum.find(make_pair(pid,param[j].first));
            assert(it != feat_sum.end());
            if (it == feat_sum.end())
                throw runtime_error("broken training data: some <pid, oid> in params not found in training data");

            observ[j] = it->second; // Ep<f_i> = sum C(f_i)*f_i
        }
    }

    if (!m_sigma2) {
        // We are not using a prior, so we can save log(E_ref) instead
        // to avoid unnecessary log(*) operation during gis parameter updates

        const double LOG_ZERO = log(numeric_limits<double>::min());
        for (size_t pid = 0; pid < m_params->size(); ++pid) {
            vector<pair<size_t, size_t> >& param = (*m_params)[pid];
            vector<double>& observ = (*m_observed_expects)[pid];
            for (size_t j = 0; j < param.size(); ++j) {
                observ[j] = (observ[j] == 0.0) ? LOG_ZERO : log(observ[j]);
            }
        }
    }
}

void GISTrainer::train(size_t iter, double tol) {
    if (!m_params || !m_es)
        throw runtime_error("Can not train on an empty model");

    init_trainer();

    // now enter iterations
    const double LOG_ZERO = log(numeric_limits<double>::min());
    double old_loglikelihood = 99999;
    double new_loglikelihood = 0.0;
    double acc;
    size_t correct;
    size_t best_oid;
    vector<double> q(m_n_outcomes); // q(y|x)
    boost::timer t;
    size_t niter = 0;

    display("");
    display("Starting GIS iterations...");
    display("Number of Predicates: %d", m_params->size());
    display("Number of Outcomes:   %d", m_n_outcomes);
    display("Number of Parameters: %d", m_n_theta);
    display("Tolerance:            %E", tol);
    display("Gaussian Penalty:     %s", (m_sigma2?"on":"off"));
#if defined(NDEBUG)
    display("Optimized version");
#endif
    display("iters   loglikelihood    training accuracy   heldout accuracy");
    display("=============================================================");

    for (; niter < iter;) {
        new_loglikelihood = 0.0;
        correct = 0;

        // computer modifiers for all features from training data
        for (vector<Event>::iterator it = m_es->begin();
                it != m_es->end(); ++it) {
            best_oid = eval(it->m_context, it->context_size(), q);
            if (best_oid == it->m_outcome)
                correct += it->m_count;
            // TODO:optimize the code
            // calculate Eq<f_i> = \sum q(y|x) * Count(f_i) * f_i(x, y)
            // (need not being divided by N)
            for (size_t i = 0; i < it->context_size(); ++i) {
                size_t pid = it->m_context[i].first;
                double fval = it->m_context[i].second;
                vector<pair<size_t, size_t> >& param = (*m_params)[pid];
                for (size_t j = 0; j < param.size(); ++j) {
                    size_t oid = param[j].first;
                    (*m_modifiers)[pid][j] += q[oid] * it->m_count * fval;
                    // binary case: (*m_modifiers)[pid][j] += q[oid] * it->m_count;
                }
            }
            assert(finite(q[it->m_outcome]));
            double t = log(q[it->m_outcome]);
            new_loglikelihood += (finite(t) ? t : LOG_ZERO) * it->m_count;
            assert(finite(new_loglikelihood));
        }
        acc = correct/double(m_N);

        // compute the new parameter values
        if (m_sigma2) { // applying Gaussian penality
            for (size_t pid = 0; pid < m_params->size(); ++pid) {
                vector<pair<size_t, size_t> >& param = (*m_params)[pid];
                for (size_t i = 0; i < param.size(); ++i) {
                    size_t fid = param[i].second;
                    m_theta[fid] += newton((*m_modifiers)[pid][i],
                            (*m_observed_expects)[pid][i], fid);
                    (*m_modifiers)[pid][i] = 0.0; // clear modifiers for next iteration
                }
            }
        } else {
            for (size_t pid = 0; pid < m_params->size(); ++pid) {
                vector<pair<size_t, size_t> >& param = (*m_params)[pid];
                for (size_t i = 0; i < param.size(); ++i) {
                    if ((*m_modifiers)[pid][i] != 0.0) {
                        m_theta[param[i].second] +=
                            ((*m_observed_expects)[pid][i] -
                             log((*m_modifiers)[pid][i])) / m_correct_constant;
                        (*m_modifiers)[pid][i] = 0.0; // clear modifiers for next iteration
                    } else {
                        // E_q == 0 means feature value is 0, which means
                        // update for this parameter will always be zero,
                        // hence can be ignored.
                    }
                }
            }
        }

        ++niter;
        display("%3d\t%E\t  %.3f%%\t     %s",
                niter , (new_loglikelihood/m_N) , (acc*100) ,  "N/A");
        if (fabs((old_loglikelihood - new_loglikelihood)/old_loglikelihood) < tol) {
            display("Training terminats succesfully in %.2f seconds", t.elapsed());
            break;
        }
        old_loglikelihood = new_loglikelihood;
    }
    if (niter >= iter)
        display("Maximum numbers of %d iterations reached in %.2f seconds", iter , t.elapsed());

    // kill a bunch of these big objects now that we don't need them
    m_modifiers.reset();
    m_observed_expects.reset();
}

// Calculate the ith GIS parameter updates with Gaussian prior
// using Newton-Raphson method
// the update rule is the solution of the following equation:
//                                   lambda_i + delta_i
// E_ref = E_q * exp (C * delta_i) + ------------------ * N
//                                       sigma_i^2
// note: E_ref and E_q were not divided by N
double GISTrainer::newton(double f_q, double f_ref, size_t i, double tol) {
    size_t maxiter = 50;
    double x0 = 0.0;
    double x = 0.0;

    for (size_t iter = 1; iter <= maxiter; ++iter) {
        double t = f_q * exp(m_correct_constant * x0);
        double fval = t + m_N * (m_theta[i] + x0) / m_sigma2[i] - f_ref;
        double fpval = t * m_correct_constant + m_N / m_sigma2[i];
        if (fpval == 0) {
            cerr <<
                "Warning: zero-derivative encountered in newton() method."
                << endl;
            return x0;
        }
        x = x0 - fval/fpval;
        if (abs(x-x0) < tol)
            return x;
        x0 = x;
    }
    throw runtime_error("Failed to converge after 50 iterations in newton() method");
}

} // namespace maxent


/*
* LEGAL NOTICE
* This computer software was prepared by Battelle Memorial Institute,
* hereinafter the Contractor, under Contract No. DE-AC05-76RL0 1830
* with the Department of Energy (DOE). NEITHER THE GOVERNMENT NOR THE
* CONTRACTOR MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY
* LIABILITY FOR THE USE OF THIS SOFTWARE. This notice including this
* sentence must appear on any copies of this computer software.
*
* EXPORT CONTROL
* User agrees that the Software will not be shipped, transferred or
* exported into any country or used in any manner prohibited by the
* United States Export Administration Act or any other applicable
* export laws, restrictions or regulations (collectively the "Export Laws").
* Export of the Software may require some form of license or other
* authority from the U.S. Government, and failure to obtain such
* export control license may result in criminal liability under
* U.S. laws. In addition, if the Software is identified as export controlled
* items under the Export Laws, User represents and warrants that User
* is not a citizen, or otherwise located within, an embargoed nation
* (including without limitation Iran, Syria, Sudan, Cuba, and North Korea)
*     and that User is not otherwise prohibited
* under the Export Laws from receiving the Software.
*
* Copyright 2011 Battelle Memorial Institute.  All Rights Reserved.
* Distributed as open-source under the terms of the Educational Community
* License version 2.0 (ECL 2.0). http://www.opensource.org/licenses/ecl2.php
*
* For further details, see: http://www.globalchange.umd.edu/models/gcam/
*
*/

/*!
* \file solver_library.cpp
* \ingroup Objects
* \brief SolverLibrary class source file.
* \author Josh Lurz
*/
#include "util/base/include/definitions.h"

#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>
#include "util/base/include/definitions.h"
#include <vector>
#include <map>
#include <cmath>
#include <string>
#include <algorithm>
#include "solution/util/include/solver_library.h"
#include "marketplace/include/marketplace.h"
#include "containers/include/world.h"
#include "util/base/include/configuration.h"
#include "util/base/include/util.h"
#include "solution/util/include/solution_info.h"
#include "solution/util/include/solution_info_set.h"
#include "solution/util/include/calc_counter.h"
#include "util/logger/include/ilogger.h"
#include "solution/util/include/ublas-helpers.hpp"
#include "containers/include/iactivity.h"

#include "solution/util/include/edfun.hpp"
#include "solution/util/include/functor-subs.hpp"

using namespace std;

#define NO_REGIONAL_DERIVATIVES 0

/*! \brief Calculate and return a relative excess demand.
* \author Josh Lurz
* \details This function determines the excess demand relative to the demand. This helps to determine which market is truely
* the worst. This function returns 0 if the ED value is below the excessDemandFloor as the market is considered solved.
* Otherwise, relative excess demand is determined to be the absolute value of excess demand divided by demand multiplied by 100.
* \param excessDemand The excess demand.
* \param demand The market demand.
* \param excessDemandFloor Value of ED below which the market should be considered solved.
* \return The relative excess demand, excess demand as a percentage of demand.
*/
double SolverLibrary::getRelativeED( const double excessDemand, const double demand, const double excessDemandFloor ) {

    // Initialize return value
    double retValue = 0;
    double tempDemand = fabs( demand );

    // If demand is 0, set tempDemand to small number to avoid
    // divide by 0.
    if( tempDemand < util::getSmallNumber() ) {
        tempDemand = util::getSmallNumber();
    }

    // Check if the ED is below a minimal value.
    if( fabs( excessDemand ) < excessDemandFloor ) {
        retValue = 0;
    }
    // Find the ratio of excess demand to demand.
    else {
        retValue = fabs( excessDemand ) / tempDemand;
    }

    return retValue;
}

/*! \brief Determine whether a market is within the solution tolerance.
* \author Josh Lurz
* \details This function determines if a market is solved to within the solution tolerance. It does this by checking if the
* relative excess demand is less than the solution tolerance.
* \param excessDemand The excess demand.
* \param demand The market demand.
* \param solutionTolerance The relative excess demand below which a market is considered solved.
* \param excessDemandFloor Absolute value of ED below which the market should be considered solved.
*/
bool SolverLibrary::isWithinTolerance( const double excessDemand, const double demand, const double solutionTolerance, const double excessDemandSolutionFloor ) {
    return ( getRelativeED( excessDemand, demand, excessDemandSolutionFloor ) < solutionTolerance );
}

/*! \brief Function to calculate partial derivatives for Newton-Raphson method, NR_Ron()
*
* This function calculates matrices of partial derivatives of supplies and demands for all markets which are currently being solved.
* The function uses the fact that changing a price while holding all other prices constant can only change markets that are affected.
* It must however set the Marketplace mIsDerivativeCalc flag to ensure only changes are noted so the non-affected markets do not need
* to null supplies and demands nor recalculate what they were.
* \param marketplace The marketplace to perform derivative calculations on.
* \param world The world object which is used for calls to World::calc
* \param aSolutionSet The vector of SolutionInfo objects which store the current prices, supplies and demands.
* \param Delta to use when changing prices.
* \param per The current model period.
*/
void SolverLibrary::derivatives( Marketplace* marketplace, World* world, SolutionInfoSet& aSolutionSet,
                                 const double aDeltaPrice, const int per ) {

    // TODO: could fix but why?
    /*ILogger& solverLog = ILogger::getLogger( "solver_log" );
    solverLog.setLevel( ILogger::NOTICE );
    solverLog << "Starting derivative calculation" << endl;

    // Initial call to world.calc to ensure we have set our baseline to take
    // partials from.
    marketplace->nullSuppliesAndDemands( per );
    world->calc( per );

#if( !NO_REGIONAL_DERIVATIVES )
    // Set the flag to only take supply/demand differences
    marketplace->mIsDerivativeCalc = true;
#endif
    // Retain the original values.
    aSolutionSet.storeValues();

    // Calculate derivatives for each market.
    for ( unsigned int j = 0; j < aSolutionSet.getNumSolvable(); j++ ) {
        double currDeltaPrice = aSolutionSet.getSolvable( j ).getDeltaPrice( aDeltaPrice );
        aSolutionSet.getSolvable( j ).increaseX( currDeltaPrice, currDeltaPrice );

#if( NO_REGIONAL_DERIVATIVES )
        marketplace->nullSuppliesAndDemands( per );
        world->calc( per );
#else

        // Determine which calculations are affected.
        const vector<IActivity*>& affectedItems = aSolutionSet.getSolvable( j ).getDependencies();

        /*! \invariant There is at least one item to calculate. * /
        assert( !affectedItems.empty() );

        world->calc( per, affectedItems );

        // Set the stale flag to indicate that demand calculations may need to
        // recalculate it's corresponding price calculation.  Setting this flag
        // allows this to be lazy.
        for( size_t partialIndex = 0 ; partialIndex < affectedItems.size(); ++partialIndex ) {
            affectedItems[ partialIndex ]->setStale();
        }
#endif

        aSolutionSet.getSolvable( j ).calcDemandElas( aSolutionSet );
        aSolutionSet.getSolvable( j ).calcSupplyElas( aSolutionSet );
        aSolutionSet.restoreValues();
    }
#if( !NO_REGIONAL_DERIVATIVES )
    // Reset the derivative flag.
    marketplace->mIsDerivativeCalc = false;
#endif
*/
}

/* \brief Calculate the JFDM, JFSM, and JF matrices from the derivatives stored in the SolutionInfo. */
void SolverLibrary::updateMatrices( SolutionInfoSet& aSolutionSet, Matrix& JFSM, Matrix& JFDM, Matrix& JF ){
    for( unsigned int j = 0; j < aSolutionSet.getNumSolvable(); ++j ){
        for( unsigned int i = 0; i < aSolutionSet.getNumSolvable(); ++i ){
            JFDM( i , j ) = aSolutionSet.getSolvable( j ).getDemandElasWithRespectTo( i );
            JFSM( i , j ) = aSolutionSet.getSolvable( j ).getSupplyElasWithRespectTo( i );
            JF( i , j ) = JFSM( i , j ) - JFDM( i , j );
            assert( util::isValidNumber( JF( i , j) ) );
        }
    }

}

/*! \brief Calculate and set new market prices based on Log NR  mechanism
 * \param aSolutionSet An object containing the set of SolutionInfo objects representing all markets.
 * \param JFLUFactorized LU factored JF matrix
 * \param aPermMatrix Permutation matrix used to factorize JF
 * \param aDefaultMaxPriceJump The default factor used to limit the price changes from this algorithm.
 * \return Whether prices were set successfully.
 */
bool SolverLibrary::calculateNewPricesLogNR( SolutionInfoSet& aSolutionSet, Matrix& JFLUFactorized,
                                             PermutationMatrix& aPermMatrix, const double aDefaultMaxPriceJump )
{
    using namespace boost::numeric::ublas;
    boost::numeric::ublas::vector<double> KDS( aSolutionSet.getNumSolvable() ); // k values demand - supply

    // initialize KDS as logs of original demand - supply or -F(Xn)
    for ( unsigned int i = 0; i < aSolutionSet.getNumSolvable(); i++ ) {
        KDS[ i ] = log( max( aSolutionSet.getSolvable( i ).getDemand(), util::getSmallNumber() ) )
            - log( max( aSolutionSet.getSolvable( i ).getSupply(), util::getSmallNumber() ) );
    }

    // Store the solution set prices so that they can be restored if NR fails to
    // generate valid prices.
    std::vector<double> storedPrices = storePrices( aSolutionSet );
    boost::numeric::ublas::vector<double> price(aSolutionSet.getNumSolvable());
    std::copy(storedPrices.begin(),storedPrices.begin()+price.size(),price.begin());

    ILogger &solverLog = ILogger::getLogger("solver_log");
    solverLog.setLevel(ILogger::DEBUG);
    solverLog << "x: " << price << "\nfx: " << KDS << "\n";

    // to solve JF(Xn) * ( Xn+1 - Xn ) = -F(Xn) we use lu substitution which
    // is favorable to calculating the inverse of JF.  lu_substitue will leave
    // us with ( Xn+1 - Xn ) stored in KDS
    lu_substitute( JFLUFactorized, aPermMatrix, KDS );
    solverLog << "dx: " << KDS << "\n";

    // To calculate the new price Xn+1 we do Xn+1 = Xn + KDS
    // then take the e^Xn+1 to get the prices back in normal terms
    for ( unsigned int i = 0; i < aSolutionSet.getNumSolvable(); i++ ) {
        // we must take the log of the current prices before adding it to KDS
        // to put them in the same domain
        double newPrice = exp( log( aSolutionSet.getSolvable( i ).getPrice() ) + KDS[ i ] );
        if( util::isValidNumber( newPrice ) ) {
            // determine a max price change to allow
            SolutionInfo& currSolutionInfo = aSolutionSet.getSolvable( i );
            double maxNRStep = currSolutionInfo.getMaxNRPriceJump( aDefaultMaxPriceJump );

            // limit the price change to avoid diverging from the solution
            // when a derivative was taken at a discontinous point
            if ( newPrice > currSolutionInfo.getPrice() * maxNRStep ){
                ILogger& solverLog = ILogger::getLogger( "solver_log" );
                solverLog.setLevel( ILogger::DEBUG );
                solverLog << currSolutionInfo.getName() << " hit max price change, " << currSolutionInfo.getPrice() << ','
                    << newPrice << ',' << currSolutionInfo.getPrice() * maxNRStep << ','
                    << newPrice / currSolutionInfo.getPrice()  << endl;
                newPrice = currSolutionInfo.getPrice() * maxNRStep;
            }
            else if ( newPrice < currSolutionInfo.getPrice() / maxNRStep ){
                ILogger& solverLog = ILogger::getLogger( "solver_log" );
                solverLog.setLevel( ILogger::DEBUG );
                solverLog << currSolutionInfo.getName() << " hit max price change, " << currSolutionInfo.getPrice() << ','
                    << newPrice << ',' << currSolutionInfo.getPrice() / maxNRStep << ','
                    << currSolutionInfo.getPrice() / newPrice << endl;
                newPrice = currSolutionInfo.getPrice() / maxNRStep;
            }

            currSolutionInfo.setPrice( newPrice );
        }
        else {
            ILogger& solverLog = ILogger::getLogger( "solver_log" );
            solverLog.setLevel( ILogger::ERROR );
            solverLog << "Correcting invalid price generated by Newton-Raphson in market "
                << aSolutionSet.getSolvable( i ).getName() << ".  Price was "
                << newPrice << endl;
            // Restore prices and return failure.
            restorePrices( aSolutionSet, storedPrices );
            return false;
        }
    }
    return true;
}

/*! \brief Calculate the LU factorization of a matrix using partial pivoting.
 * \author Pralit Patel
 * \details This function changes an input matrix to an LU factorizated version and also
 *          produces a permutation matrix. This can be used in conjunction with lu_substitue
 *          to solve a set of equations of the form Ax=b and is less computationaly intensive
 *          than finding the inverse of A and multiplying that by b.
 *          This function also checks if the matrix is singular in which case garbage may
 *          be returned since no inverse exists.  The return value should always be
 *          checked after a call to this method.
 * \param aInputMatrix Matrix that will be LU factorized.
 * \param aPermMatrix A permutation matrix that will hold the permutations used for LU decomposition.
 * \return Whether the factorization was succesful.  It may not be successful if the input matrix is
 *          is singular in which case the contents of the matrix and permutation matrix will be garbage.
 */
bool SolverLibrary::luFactorizeMatrix( Matrix& aInputMatrix, PermutationMatrix& aPermMatrix ) {
    using namespace boost::numeric::ublas;

    // need to reset the permutation matrix
    PermutationMatrix tempPerm( aInputMatrix.size1() );
    aPermMatrix.assign( tempPerm );

    // do the LU-factorization, the return value is the singular row + 1
    // and so if the return value is 0 there were no singularities
    return lu_factorize( aInputMatrix, aPermMatrix ) != 0;
}

/*! \brief Bracket a set of markets.
* \details Function finds bracket interval for each market and puts this
*          information into solution set vector
* \author Sonny Kim, Josh Lurz, Steve Smith, Kate Calvin
* \param aMarketplace Marketplace reference.
* \param aWorld World reference.
* \param aDefaultBracketInterval The default bracket interval by which trial values are moved
*                                which may be overriden by a SolutionInfo.  The bracket interval
*                                is used as the multiplier to expand trial brackets.
* \param aMaxIterations The maximum iterations allowed to find a brackets.
* \param aSolutionSet Vector of market solution information
* \param aCalcCounter The calculation counter.
* \param aPeriod Model period
* \return Whether bracketing of all markets completed successfully.
*/
bool SolverLibrary::bracket( Marketplace* aMarketplace, World* aWorld, const double aDefaultBracketInterval,
                             const unsigned int aMaxIterations, SolutionInfoSet& aSolutionSet, CalcCounter* aCalcCounter,
                             const ISolutionInfoFilter* aSolutionInfoFilter, const int aPeriod )
{
    bool code = false;
    static const double LOWER_BOUND = util::getVerySmallNumber();

    // Make sure the markets are up to date before starting.
    aMarketplace->nullSuppliesAndDemands( aPeriod );
#if GCAM_PARALLEL_ENABLED
    aWorld->calc( aPeriod, aWorld->getGlobalFlowGraph() );
#else
    aWorld->calc( aPeriod );
#endif
    aSolutionSet.updateSolvable( aSolutionInfoFilter );
    // Return with code true if all markets are bracketed.
    if( aSolutionSet.isAllBracketed() ){
        return code = true;
    }
    aSolutionSet.resetBrackets();

    ILogger& solverLog = ILogger::getLogger( "solver_log" );
    solverLog.setLevel( ILogger::NOTICE );
    solverLog << "Entering bracketing" << endl;

    if( aSolutionSet.getNumSolvable() == 0 ) {
        solverLog << "Exiting bracketing early due to empty solvable set." << endl;
        return true;
    }

    // Set up the EDFun wrapper which we will use to do the model evaluations.
    // This way we can re-use the same concepts to backtrack on a bracket step
    // similar to how we do it in the linesearch algorithm used in NR.
    using UBVECTOR = boost::numeric::ublas::vector<double>;
    LogEDFun edFun(aSolutionSet, aWorld, aMarketplace, aPeriod, false);
    FdotF<double, double> F(edFun);
    UBVECTOR x(aSolutionSet.getNumSolvable());
    UBVECTOR prev_x(aSolutionSet.getNumSolvable());
    UBVECTOR dx(aSolutionSet.getNumSolvable());
    for(int i = 0; i < aSolutionSet.getNumSolvable(); ++i) {
        x[i] = aSolutionSet.getSolvable(i).getPrice();
    }
    edFun.scaleInitInputs(x);
    double currFX = F(x);
    double prevFX;

    solverLog.setLevel( ILogger::DEBUG );
    solverLog << aSolutionSet << endl;
    solverLog << endl << "Initial FX: " << currFX << endl;

    ILogger& singleLog = ILogger::getLogger( "single_market_log" );

    // Loop is done at least once.
    unsigned int iterationCount = 1;
    do {
        prev_x = x;
        prevFX = currFX;
        aSolutionSet.printMarketInfo( "Bracket All", aCalcCounter->getPeriodCount(), singleLog );

        // Iterate through each market.
        for ( unsigned int i = 0; i < aSolutionSet.getNumSolvable(); i++ ) {
            // Fetch the current
            SolutionInfo& currSol = aSolutionSet.getSolvable( i );
            double currBracketInterval = currSol.getBracketInterval( aDefaultBracketInterval );

            // Check for special case where a resource with no supply can become "solved" during
            // the bracketing procedure.
            if( fabs( currSol.getSupply() ) < util::getSmallNumber() &&
                fabs( currSol.getDemand() ) < util::getSmallNumber() )
            {
                currSol.setBracketed();
            }
            if ( !currSol.isBracketed() ) {
                // If a market is not bracketed, then EDL and EDR have the same sign
                // Check if ED has the same sign as EDL and EDR.
                if ( util::sign( currSol.getED() ) == util::sign( currSol.getEDLeft() ) ) {
                    // If Supply > Demand at point X, then we want to decrease x to increase demand
                    // If ED is negative, then so are EDL and EDR
                    // So, X, XL, and XR are all greater than the solution price
                    if ( currSol.getED() < 0 ) {
                        currSol.moveRightBracketToX();
                        currSol.decreaseX( currBracketInterval, LOWER_BOUND );
                    } // END: if statement testing if ED < 0
                    // If Supply <= Demand. Price needs to increase so demand decreases
                    // If ED is positive, then so are EDL and EDR
                    // So, X, XL, and XR are all less than the solution price
                    else {
                        currSol.moveLeftBracketToX();
                        currSol.increaseX( currBracketInterval, LOWER_BOUND );
                    } // END: if statement testing if ED > 0
                } // END: if statement testing if ED and EDL have the same sign
                // If market is unbracketed, EDL and EDR have the same sign
                // ED has the opposite sign of EDL and EDR
                else {
                    // If ED < 0, then EDL > 0 and EDR > 0
                    // To bracket we just need to move XR to X
                    if ( currSol.getED() < 0 ) {
                        currSol.moveRightBracketToX();
                    } // END: if statement testing if ED < 0
                    // If ED > 0, then EDL < 0 and EDR < 0
                    // To bracket, we just need to move XL to X
                    else {
                        currSol.moveLeftBracketToX();
                    } // END: if statement testing if ED > 0
                } // END: if statement testing if ED and EDL have opposite signs

                // Check if current marketed is now bracketed
                // If so, set bracketed to true
                if( currSol.isCurrentlyBracketed() ){
                    currSol.setBracketed();
                }

            } // END: if statement testing if bracketed
            // If bracketed, but left and right prices are equal
            else if ( currSol.getBracketSize() == 0 ){
                // If XL and XR are equal, market is not bracketed
                // If ED, EDL and EDR all have same sign, set bracketed to false
                if ( util::sign( currSol.getED() ) == util::sign( currSol.getEDLeft() ) ) {
                    currSol.resetBrackets();
                }
                // if ED < EDL, then X > XL
                // if we move XR to X, then market will be bracketed
                else if ( currSol.getED() < currSol.getEDLeft() ) {
                    currSol.moveRightBracketToX();

                    // Check if market is currently bracketed
                    // If so, set bracketed to true
                    if( currSol.isCurrentlyBracketed() ){
                        currSol.setBracketed();
                    }
                }
                // if ED > EDL, then X < XL
                // if we move XL to X, then market will be bracketed
                else {
                    currSol.moveLeftBracketToX();

                    // Check if market is currently bracketed
                    // If so, set bracketed to true
                    if( currSol.isCurrentlyBracketed() ){
                        currSol.setBracketed();
                    }
                }
            } // END: if statement testing if currSol is bracketed with XL == XR
            x[i] = currSol.getPrice();
        } // end for loop

        // Rescale prices to be normalized then run an iteration
        edFun.scaleInitInputs(x);
        currFX = F(x);
        solverLog << "Current FX: " << currFX << endl;

        // Check if this bracket step has increased the "error" F dot F by more than the
        // allowable threshold and walk back the step by half until it no longer does.
        const double FX_INCREASE_THRESHOLD = 10.0;
        double stepMult = 1.0;
        dx = x - prev_x;
        while(currFX > (prevFX * FX_INCREASE_THRESHOLD)) {
            stepMult /= 2.0;
            x = prev_x + dx * stepMult;
            currFX = F(x);
            solverLog << "Walked back: " << stepMult << ", Current FX: " << currFX << endl;
        }
        solverLog.setLevel( ILogger::NOTICE );
        solverLog << "Completed an iteration of bracket: " << iterationCount << endl;
        solverLog << aSolutionSet << endl;
    } while ( ++iterationCount <= aMaxIterations && !aSolutionSet.isAllBracketed() );

    code = ( aSolutionSet.isAllBracketed() ? true : false );

    solverLog.setLevel( ILogger::DEBUG );
    solverLog << "Solution Info Set before leaving bracket: " << endl;
    solverLog << aSolutionSet << endl;

    aSolutionSet.printMarketInfo( "End Bracketing Attempt", 0, singleLog );

    return code;
}

/*
 * \brief Function finds bracket interval for a single market.
 * \author Josh Lurz
 * \param aMarketplace Marketplace reference.
 * \param aWorld World reference.
 * \param aDefaultBracketInterval The default bracket interval by which trial values are moved
 *                                which may be overriden by a SolutionInfo.  The bracket interval
 *                                is used as the multiplier to expand trial brackets.
 * \param aMaxIterations The maximum iterations allowed to find a brackets.
 * \param aSolSet The solution info set.
 * \param aSol The solution info to bracket.
 * \param aCalcCounter The calculation counter.
 * \param period Model period
 * \return Whether the market was successfully bracketed.
 */
bool SolverLibrary::bracketOne( Marketplace* aMarketplace, World* aWorld, const double aDefaultBracketInterval,
                                const unsigned int aMaxIterations, SolutionInfoSet& aSolSet, SolutionInfo* aSol,
                                CalcCounter* aCalcCounter, const ISolutionInfoFilter* aSolutionInfoFilter, const int aPeriod )
{
    static const double LOWER_BOUND = util::getSmallNumber();

    aSolSet.updateSolvable( aSolutionInfoFilter );
    double bracketInterval = aSol->getBracketInterval( aDefaultBracketInterval );

    // Logging
    ILogger& solverLog = ILogger::getLogger( "solver_log" );
    solverLog.setLevel( ILogger::NOTICE );
    solverLog << "Entering single market bracketing for market " << aSol->getName() << "." << endl;
    solverLog.setLevel( ILogger::DEBUG );
    solverLog << "Solution info set prior to bracket one." << endl;
    solverLog << aSolSet << endl;

    ILogger& singleLog = ILogger::getLogger( "single_market_log" );

    aSol->resetBrackets();
    unsigned int numIterations = 0;

    // Loop is done at least once.
    do {
        aSolSet.printMarketInfo( "Bracket One on " + aSol->getName(),
                                 aCalcCounter->getPeriodCount(),
                                 singleLog );

        // If ED at X and L are the same sign.
        if ( util::sign( aSol->getED() ) == util::sign( aSol->getEDLeft() ) ) {
            // If Supply > Demand at point X.
            if ( aSol->getED() < 0 ) {
                aSol->moveRightBracketToX();
                if( !aSol->isCurrentlyBracketed() ){
                    aSol->decreaseX( bracketInterval, LOWER_BOUND );
                }
                else {
                    aSol->setBracketed();
                }
            }
            else { // If Supply <= Demand. Price needs to increase.
                aSol->moveLeftBracketToX();
                if( !aSol->isCurrentlyBracketed() ){
                    aSol->increaseX( bracketInterval, LOWER_BOUND );
                }
                else {
                    aSol->setBracketed();
                }
            }
        }
        else {  // ED at X and R are the same sign.
            if ( aSol->getED() < 0 ) { // If Supply > Demand at X.
                aSol->moveRightBracketToX();
                if( !aSol->isCurrentlyBracketed() ){
                    aSol->decreaseX( bracketInterval, LOWER_BOUND );
                }
                else {
                    aSol->setBracketed();
                }
            }
            else { // If Supply <= Demand at X. Prices need to increase.
                aSol->moveLeftBracketToX();
                if( !aSol->isCurrentlyBracketed() ){
                    aSol->increaseX( bracketInterval, LOWER_BOUND );
                }
                else {
                    aSol->setBracketed();
                }
            }
        }
        // Check if the market is actually solved.
        if( aSol->isSolved() ){
            aSol->setBracketed();
            aSol->moveLeftBracketToX();
            aSol->moveRightBracketToX();
        }

        aMarketplace->nullSuppliesAndDemands( aPeriod );
        aWorld->calc( aPeriod );
        aSolSet.updateSolvable( aSolutionInfoFilter );
        solverLog.setLevel( ILogger::NOTICE );
        solverLog << "Completed an iteration of bracketOne." << endl;
        solverLog << *aSol << endl;
    } while ( ++numIterations < aMaxIterations && !aSol->isBracketed() );

    solverLog.setLevel( ILogger::NOTICE );
    solverLog << "Exiting single market bracketing." << endl;
    solverLog.setLevel( ILogger::DEBUG );
    solverLog << "Solution info set after bracket one." << endl;
    solverLog << aSolSet << endl;

    return aSol->isBracketed();
}

/*! \brief Store the current prices in the solver set in a vector.
* \param aSolutionSet Solution set.
* \return Vector of prices currently in the solver set.
*/
vector<double> SolverLibrary::storePrices( const SolutionInfoSet& aSolutionSet ){
    vector<double> storedPrices;
    for( unsigned int i = 0; i < aSolutionSet.getNumTotal(); ++i ){
        storedPrices.push_back( aSolutionSet.getAny( i ).getPrice() );
    }
    return storedPrices;
}

/*! \brief Restore prices in the solver set to the values of a given vector.
* \param aSolutionSet Solution set.
* \param aPrices Prices to set into the solver set.
*/
void SolverLibrary::restorePrices( SolutionInfoSet& aSolutionSet, const vector<double>& aPrices ){
    /*! \pre One price per market. */
    assert( aSolutionSet.getNumTotal() == aPrices.size() );
    for( unsigned int i = 0; i < aSolutionSet.getNumTotal(); ++i ){
        aSolutionSet.getAny( i ).setPrice( aPrices[ i ] );
    }
}


// $Id$
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
//  Contribution from Roger Sayle
#include <vector>
#include "Pubchem.h"
#include <DataStructs/ExplicitBitVect.h>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/Substruct/SubstructMatch.h>
#include <GraphMol/MolOps.h>

#include <RDGeneral/BoostStartInclude.h>
#include <boost/flyweight.hpp>
#include <boost/flyweight/no_tracking.hpp>
#include <RDGeneral/BoostEndInclude.h>

namespace {
struct Patterns {
  std::unique_ptr<RDKit::ROMol> bit_8 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]1~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_11 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*1~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_13 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#7](~[#6])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_14 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]-[#16]"));
  std::unique_ptr<RDKit::ROMol> bit_15 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#6](~[#8])~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_16 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]1~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_17 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]#[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_19 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*1~*~*~*~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_20 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#14]"));
  std::unique_ptr<RDKit::ROMol> bit_21 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#6]=[#6](~[!#6!#1])~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_22 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*1~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_23 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#7]~[#6](~[#8])~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_24 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]-[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_25 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#7]~[#6](~[#7])~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_26 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=@[#6](@*)@*"));
  std::unique_ptr<RDKit::ROMol> bit_28 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1]~[CH2]~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_30 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#6]~[!#6!#1](~[#6])(~[#6])~*"));
  std::unique_ptr<RDKit::ROMol> bit_31 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[F,Cl,Br,I]"));
  std::unique_ptr<RDKit::ROMol> bit_32 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]~[#16]~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_33 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~[#16]"));
  std::unique_ptr<RDKit::ROMol> bit_34 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH2]=*"));
  std::unique_ptr<RDKit::ROMol> bit_36 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16R]"));
  std::unique_ptr<RDKit::ROMol> bit_37 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#7]~[#6](~[#8])~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_38 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#7]~[#6](~[#6])~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_39 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#16](~[#8])~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_40 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]-[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_41 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]#[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_43 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1!H0]~*~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_44 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol(
          "[!#1;!#6;!#7;!#8;!#9;!#14;!#15;!#16;!#17;!#35;!#53]"));
  std::unique_ptr<RDKit::ROMol> bit_45 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=[#6]~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_47 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]~*~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_48 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[!#6!#1](~[#8])~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_49 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!+0]"));
  std::unique_ptr<RDKit::ROMol> bit_50 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#6]=[#6](~[#6])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_51 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]~[#16]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_52 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_53 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1!H0]~*~*~*~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_54 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1!H0]~*~*~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_55 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]~[#16]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_56 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#7](~[#8])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_57 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8R]"));
  std::unique_ptr<RDKit::ROMol> bit_58 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1]~[#16]~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_59 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]!:*:*"));
  std::unique_ptr<RDKit::ROMol> bit_60 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]=[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_61 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[#16](~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_62 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*@*!@*@*"));
  std::unique_ptr<RDKit::ROMol> bit_63 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]=[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_64 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*@*!@[#16]"));
  std::unique_ptr<RDKit::ROMol> bit_65 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("c:n"));
  std::unique_ptr<RDKit::ROMol> bit_66 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#6]~[#6](~[#6])(~[#6])~*"));
  std::unique_ptr<RDKit::ROMol> bit_67 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[#16]"));
  std::unique_ptr<RDKit::ROMol> bit_68 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1!H0]~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_69 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_70 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1]~[#7]~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_71 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_72 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]~*~*~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_73 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]=*"));
  std::unique_ptr<RDKit::ROMol> bit_74 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH3]~*~[CH3]"));
  std::unique_ptr<RDKit::ROMol> bit_75 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*!@[#7]@*"));
  std::unique_ptr<RDKit::ROMol> bit_76 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=[#6](~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_77 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_78 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_79 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~*~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_80 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~*~*~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_81 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#16]~*(~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_82 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[CH2]~[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_83 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]1~*~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_84 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[NH2]"));
  std::unique_ptr<RDKit::ROMol> bit_85 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#6]~[#7](~[#6])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_86 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[C;H2,H3][!#6!#1][C;H2,H3]"));
  std::unique_ptr<RDKit::ROMol> bit_87 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[F,Cl,Br,I]!@*@*"));
  std::unique_ptr<RDKit::ROMol> bit_89 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]~*~*~*~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_90 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[$([!#6!#1!H0]~*~*~[CH2]~*),$([!#6!#1!H0R]1@[R]@[R]@["
                         "CH2R]1),$([!#6!#1!H0]~[R]1@[R]@[CH2R]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_91 = std::unique_ptr<
      RDKit::ROMol>(RDKit::SmartsToMol(
      "[$([!#6!#1!H0]~*~*~*~[CH2]~*),$([!#6!#1!H0R]1@[R]@[R]@[R]@[CH2R]1),$([!#"
      "6!#1!H0]~[R]1@[R]@[R]@[CH2R]1),$([!#6!#1!H0]~*~[R]1@[R]@[CH2R]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_92 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#6](~[#7])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_93 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[CH3]"));
  std::unique_ptr<RDKit::ROMol> bit_94 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_95 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~*~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_96 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*1~*~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_97 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~*~*~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_98 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1]1~*~*~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_99 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_100 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[CH2]~[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_101 = std::unique_ptr<
      RDKit::ROMol>(RDKit::SmartsToMol(
      "[$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@[R]@1),$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@["
      "R]@[R]@1),$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@1),$([R]1@[R]@[R]@["
      "R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@1),$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]"
      "@[R]@[R]@[R]@1),$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@"
      "1),$([R]1@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@[R]@1)]"));
  std::unique_ptr<RDKit::ROMol> bit_102 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_104 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1!H0]~*~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_105 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*@*(@*)@*"));
  std::unique_ptr<RDKit::ROMol> bit_106 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[!#6!#1]~*(~[!#6!#1])~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_107 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[F,Cl,Br,I]~*(~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_108 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH3]~*~*~*~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_109 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[CH2]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_110 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~[#6]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_111 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_112 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~*(~*)(~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_113 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]!:*:*"));
  std::unique_ptr<RDKit::ROMol> bit_114 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH3]~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_115 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH3]~*~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_116 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[$([CH3]~*~*~[CH2]~*),$([CH3]~*1~*~[CH2]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_117 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_118 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[$(*~[CH2]~[CH2]~*),$(*1~[CH2]~[CH2]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_119 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]=*"));
  std::unique_ptr<RDKit::ROMol> bit_120 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6R]"));
  std::unique_ptr<RDKit::ROMol> bit_121 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7R]"));
  std::unique_ptr<RDKit::ROMol> bit_122 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[#7](~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_123 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]~[#6]~[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_124 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[!#6!#1]"));
  std::unique_ptr<RDKit::ROMol> bit_126 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*!@[#8]!@*"));
  std::unique_ptr<RDKit::ROMol> bit_127 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*@*!@[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_128 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol(
          "[$(*~[CH2]~*~*~*~[CH2]~*),$([R]1@[CH2R]@[R]@[R]@[R]@[CH2R]1),$(*~["
          "CH2]~[R]1@[R]@[R]@[CH2R]1),$(*~[CH2]~*~[R]1@[R]@[CH2R]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_129 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[$(*~[CH2]~*~*~[CH2]~*),$([R]1@[CH2]@[R]@[R]@[CH2R]1)"
                         ",$(*~[CH2]~[R]1@[R]@[CH2R]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_131 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_132 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]~*~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_133 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*@*!@[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_135 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]!:*:*"));
  std::unique_ptr<RDKit::ROMol> bit_136 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]=*"));
  std::unique_ptr<RDKit::ROMol> bit_137 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!C!cR]"));
  std::unique_ptr<RDKit::ROMol> bit_138 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[!#6!#1]~[CH2]~*"));
  std::unique_ptr<RDKit::ROMol> bit_139 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[O!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_140 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_141 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[CH3]"));
  std::unique_ptr<RDKit::ROMol> bit_142 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_144 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*!:*:*!:*"));
  std::unique_ptr<RDKit::ROMol> bit_145 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*1~*~*~*~*~*~1"));
  std::unique_ptr<RDKit::ROMol> bit_147 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[$(*~[CH2]~[CH2]~*),$([R]1@[CH2R]@[CH2R]1)]"));
  std::unique_ptr<RDKit::ROMol> bit_148 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*~[!#6!#1](~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_149 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[C;H3,H4]"));
  std::unique_ptr<RDKit::ROMol> bit_150 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*!@*@*!@*"));
  std::unique_ptr<RDKit::ROMol> bit_151 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7!H0]"));
  std::unique_ptr<RDKit::ROMol> bit_152 = std::unique_ptr<RDKit::ROMol>(
      RDKit::SmartsToMol("[#8]~[#6](~[#6])~[#6]"));
  std::unique_ptr<RDKit::ROMol> bit_154 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]=[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_155 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("*!@[CH2]!@*"));
  std::unique_ptr<RDKit::ROMol> bit_156 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#7]~*(~*)~*"));
  std::unique_ptr<RDKit::ROMol> bit_157 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]-[#8]"));
  std::unique_ptr<RDKit::ROMol> bit_158 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[#6]-[#7]"));
  std::unique_ptr<RDKit::ROMol> bit_162 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("a"));
  std::unique_ptr<RDKit::ROMol> bit_165 =
      std::unique_ptr<RDKit::ROMol>(RDKit::SmartsToMol("[R]"));
};

boost::flyweight<std::unique_ptr<Patterns>, boost::flyweights::no_tracking>
    gpats;
void GenerateFP(const RDKit::ROMol &mol, ExplicitBitVect &fp) {
  if (!gpats.get()) {
    gpats = std::unique_ptr<Patterns>(new Patterns());
  }
  const Patterns &pats = *(gpats.get());
  PRECONDITION(fp.size() == 167, "bad fingerprint");
  fp.clearBits();

  if (!mol.getNumAtoms()) {
    return;
  }

  std::vector<RDKit::MatchVectType> matches;
  RDKit::RWMol::ConstAtomIterator atom;
  RDKit::MatchVectType match;
  unsigned int count;

  for (atom = mol.beginAtoms(); atom != mol.endAtoms(); ++atom) {
    switch ((*atom)->getAtomicNum()) {
      case 3:
      case 11:
      case 19:
      case 37:
      case 55:
      case 87:
        fp.setBit(35);
        break;
      case 4:
      case 12:
      case 20:
      case 38:
      case 56:
      case 88:
        fp.setBit(10);
        break;
      case 5:
      case 13:
      case 31:
      case 49:
      case 81:
        fp.setBit(18);
        break;
      case 9:
        fp.setBit(42);
        fp.setBit(134);
        break;
      case 15:
        fp.setBit(29);
        break;
      case 16:
        fp.setBit(88);
        break;
      case 17:
        fp.setBit(103);
        fp.setBit(134);
        break;
      case 21:
      case 22:
      case 39:
      case 40:
      case 72:
        fp.setBit(5);
        break;
      case 23:
      case 24:
      case 25:
      case 41:
      case 42:
      case 43:
      case 73:
      case 74:
      case 75:
        fp.setBit(7);
        break;
      case 26:
      case 27:
      case 28:
      case 44:
      case 45:
      case 46:
      case 76:
      case 77:
      case 78:
        fp.setBit(9);
        break;
      case 29:
      case 30:
      case 47:
      case 48:
      case 79:
      case 80:
        fp.setBit(12);
        break;
      case 32:
      case 33:
      case 34:
      case 50:
      case 51:
      case 52:
      case 82:
      case 83:
      case 84:
        fp.setBit(3);
        break;
      case 35:
        fp.setBit(46);
        fp.setBit(134);
        break;
      case 53:
        fp.setBit(27);
        fp.setBit(134);
        break;
      case 57:
      case 58:
      case 59:
      case 60:
      case 61:
      case 62:
      case 63:
      case 64:
      case 65:
      case 66:
      case 67:
      case 68:
      case 69:
      case 70:
      case 71:
        fp.setBit(6);
        break;
      case 89:
      case 90:
      case 91:
      case 92:
      case 93:
      case 94:
      case 95:
      case 96:
      case 97:
      case 98:
      case 99:
      case 100:
      case 101:
      case 102:
      case 103:
        fp.setBit(4);
        break;
      case 104:
        fp.setBit(2);
        break;
    }
  }

  if (RDKit::SubstructMatch(mol, *pats.bit_8, match, true)) {
    fp.setBit(8);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_11, match, true)) {
    fp.setBit(11);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_13, match, true)) {
    fp.setBit(13);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_14, match, true)) {
    fp.setBit(14);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_15, match, true)) {
    fp.setBit(15);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_16, match, true)) {
    fp.setBit(16);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_17, match, true)) {
    fp.setBit(17);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_19, match, true)) {
    fp.setBit(19);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_20, match, true)) {
    fp.setBit(20);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_21, match, true)) {
    fp.setBit(21);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_22, match, true)) {
    fp.setBit(22);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_23, match, true)) {
    fp.setBit(23);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_24, match, true)) {
    fp.setBit(24);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_25, match, true)) {
    fp.setBit(25);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_26, match, true)) {
    fp.setBit(26);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_28, match, true)) {
    fp.setBit(28);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_30, match, true)) {
    fp.setBit(30);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_31, match, true)) {
    fp.setBit(31);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_32, match, true)) {
    fp.setBit(32);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_33, match, true)) {
    fp.setBit(33);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_34, match, true)) {
    fp.setBit(34);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_36, match, true)) {
    fp.setBit(36);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_37, match, true)) {
    fp.setBit(37);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_38, match, true)) {
    fp.setBit(38);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_39, match, true)) {
    fp.setBit(39);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_40, match, true)) {
    fp.setBit(40);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_41, match, true)) {
    fp.setBit(41);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_43, match, true)) {
    fp.setBit(43);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_44, match, true)) {
    fp.setBit(44);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_45, match, true)) {
    fp.setBit(45);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_47, match, true)) {
    fp.setBit(47);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_48, match, true)) {
    fp.setBit(48);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_49, match, true)) {
    fp.setBit(49);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_50, match, true)) {
    fp.setBit(50);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_51, match, true)) {
    fp.setBit(51);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_52, match, true)) {
    fp.setBit(52);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_53, match, true)) {
    fp.setBit(53);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_54, match, true)) {
    fp.setBit(54);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_55, match, true)) {
    fp.setBit(55);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_56, match, true)) {
    fp.setBit(56);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_57, match, true)) {
    fp.setBit(57);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_58, match, true)) {
    fp.setBit(58);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_59, match, true)) {
    fp.setBit(59);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_60, match, true)) {
    fp.setBit(60);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_61, match, true)) {
    fp.setBit(61);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_62, match, true)) {
    fp.setBit(62);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_63, match, true)) {
    fp.setBit(63);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_64, match, true)) {
    fp.setBit(64);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_65, match, true)) {
    fp.setBit(65);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_66, match, true)) {
    fp.setBit(66);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_67, match, true)) {
    fp.setBit(67);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_68, match, true)) {
    fp.setBit(68);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_69, match, true)) {
    fp.setBit(69);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_70, match, true)) {
    fp.setBit(70);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_71, match, true)) {
    fp.setBit(71);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_72, match, true)) {
    fp.setBit(72);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_73, match, true)) {
    fp.setBit(73);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_74, match, true)) {
    fp.setBit(74);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_75, match, true)) {
    fp.setBit(75);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_76, match, true)) {
    fp.setBit(76);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_77, match, true)) {
    fp.setBit(77);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_78, match, true)) {
    fp.setBit(78);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_79, match, true)) {
    fp.setBit(79);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_80, match, true)) {
    fp.setBit(80);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_81, match, true)) {
    fp.setBit(81);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_82, match, true)) {
    fp.setBit(82);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_83, match, true)) {
    fp.setBit(83);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_84, match, true)) {
    fp.setBit(84);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_85, match, true)) {
    fp.setBit(85);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_86, match, true)) {
    fp.setBit(86);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_87, match, true)) {
    fp.setBit(87);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_89, match, true)) {
    fp.setBit(89);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_90, match, true)) {
    fp.setBit(90);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_91, match, true)) {
    fp.setBit(91);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_92, match, true)) {
    fp.setBit(92);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_93, match, true)) {
    fp.setBit(93);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_94, match, true)) {
    fp.setBit(94);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_95, match, true)) {
    fp.setBit(95);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_96, match, true)) {
    fp.setBit(96);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_97, match, true)) {
    fp.setBit(97);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_98, match, true)) {
    fp.setBit(98);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_99, match, true)) {
    fp.setBit(99);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_100, match, true)) {
    fp.setBit(100);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_101, match, true)) {
    fp.setBit(101);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_102, match, true)) {
    fp.setBit(102);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_104, match, true)) {
    fp.setBit(104);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_105, match, true)) {
    fp.setBit(105);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_106, match, true)) {
    fp.setBit(106);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_107, match, true)) {
    fp.setBit(107);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_108, match, true)) {
    fp.setBit(108);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_109, match, true)) {
    fp.setBit(109);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_110, match, true)) {
    fp.setBit(110);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_111, match, true)) {
    fp.setBit(111);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_112, match, true)) {
    fp.setBit(112);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_113, match, true)) {
    fp.setBit(113);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_114, match, true)) {
    fp.setBit(114);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_115, match, true)) {
    fp.setBit(115);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_116, match, true)) {
    fp.setBit(116);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_117, match, true)) {
    fp.setBit(117);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_118, matches, true, true) > 1) {
    fp.setBit(118);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_119, match, true)) {
    fp.setBit(119);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_120, matches, true, true) > 1) {
    fp.setBit(120);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_121, match, true)) {
    fp.setBit(121);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_122, match, true)) {
    fp.setBit(122);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_123, match, true)) {
    fp.setBit(123);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_124, matches, true, true);
  if (count > 0) {
    fp.setBit(124);
  }
  if (count > 1) {
    fp.setBit(130);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_126, match, true)) {
    fp.setBit(126);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_127, matches, true, true);
  if (count > 1) {
    fp.setBit(127);
  }
  if (count > 0) {
    fp.setBit(143);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_128, match, true)) {
    fp.setBit(128);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_129, match, true)) {
    fp.setBit(129);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_131, matches, true, true) > 1) {
    fp.setBit(131);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_132, match, true)) {
    fp.setBit(132);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_133, match, true)) {
    fp.setBit(133);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_135, match, true)) {
    fp.setBit(135);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_136, matches, true, true) > 1) {
    fp.setBit(136);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_137, match, true)) {
    fp.setBit(137);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_138, matches, true, true);
  if (count > 1) {
    fp.setBit(138);
  }
  if (count > 0) {
    fp.setBit(153);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_139, match, true)) {
    fp.setBit(139);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_140, matches, true, true);
  if (count > 3) {
    fp.setBit(140);
  }
  if (count > 2) {
    fp.setBit(146);
  }
  if (count > 1) {
    fp.setBit(159);
  }
  if (count > 0) {
    fp.setBit(164);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_141, matches, true, true) > 2) {
    fp.setBit(141);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_142, matches, true, true);
  if (count > 1) {
    fp.setBit(142);
  }
  if (count > 0) {
    fp.setBit(161);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_144, match, true)) {
    fp.setBit(144);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_145, matches, true, true);
  if (count > 1) {
    fp.setBit(145);
  }
  if (count > 0) {
    fp.setBit(163);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_147, match, true)) {
    fp.setBit(147);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_148, match, true)) {
    fp.setBit(148);
  }
  count = RDKit::SubstructMatch(mol, *pats.bit_149, matches, true, true);
  if (count > 1) {
    fp.setBit(149);
  }
  if (count > 0) {
    fp.setBit(160);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_150, match, true)) {
    fp.setBit(150);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_151, match, true)) {
    fp.setBit(151);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_152, match, true)) {
    fp.setBit(152);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_154, match, true)) {
    fp.setBit(154);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_155, match, true)) {
    fp.setBit(155);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_156, match, true)) {
    fp.setBit(156);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_157, match, true)) {
    fp.setBit(157);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_158, match, true)) {
    fp.setBit(158);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_162, match, true)) {
    fp.setBit(162);
  }
  if (RDKit::SubstructMatch(mol, *pats.bit_165, match, true)) {
    fp.setBit(165);
  }

  /* BIT 125 */
  RDKit::RingInfo *info = mol.getRingInfo();
  unsigned int ringcount = info->numRings();
  unsigned int nArom = 0;
  for (unsigned int i = 0; i < ringcount; i++) {
    bool isArom = true;
    const std::vector<int> *ring = &info->bondRings()[i];
    std::vector<int>::const_iterator iter;
    for (iter = ring->begin(); iter != ring->end(); ++iter) {
      if (!mol.getBondWithIdx(*iter)->getIsAromatic()) {
        isArom = false;
        break;
      }
    }
    if (isArom) {
      if (nArom) {
        fp.setBit(125);
        break;
      } else {
        nArom++;
      }
    }
  }

  /* BIT 166 */
  std::vector<int> mapping;
  if (RDKit::MolOps::getMolFrags(mol, mapping) > 1) {
    fp.setBit(166);
  }
}
}  // namespace

namespace RDKit {
namespace MACCSFingerprints {
ExplicitBitVect *getFingerprintAsBitVect(const ROMol &mol) {
  auto *fp = new ExplicitBitVect(167);
  GenerateFP(mol, *fp);
  return fp;
}
}  // namespace MACCSFingerprints
}  // namespace RDKit