<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file moments.hpp
 * \date May 2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__DISTRIBUTION__INTERFACE__MOMENTS_HPP
#define FL__DISTRIBUTION__INTERFACE__MOMENTS_HPP

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>
#include <fl/distribution/interface/approximate_moments.hpp>

namespace fl
{

// Forward declaration
template <typename...> class Moments;

/**
 * \ingroup distribution_interfaces
 *
 * \brief Represents the interface providing the first two moments
 *
 * \tparam Variate        Random variable type. This is equivalent to the first
 *                        moment type.
 * \tparam SecondMoment   Second moment type. The second moment is either
 *                        the second uncentered moment \f$Var(X) + X^2\f$ or
 *                        simply the second central moment, the variance or
 *                        covariance \f$Var(X) = Cov(X, X)\f$. Both have the
 *                        same type \c SecondMoment.
 *
 *
 * The Moments interface provides access to the exact first moments of
 * a distribution. The moments represent a subset of the approximate moments.
 */
template <typename Variate_, typename SecondMoment_>
class Moments<Variate_, SecondMoment_>
    : public ApproximateMoments<Variate_, SecondMoment_>
{
public:
    /**
     * \brief Variate Random variable type. This is equivalent to the first
     *        moment type.
     */
    typedef Variate_ Variate;

    /**
     * \brief Second central moment type (e.g. Variance or the Covariance)
     */
    typedef SecondMoment_ SecondMoment;

    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }

    /**
     * \return First moment of the underlying distribution, the mean
     *
     * \f$ \mu = \sum\limits_i x_i p(x_i)\f$
     */
    virtual const Variate& mean() const = 0;

    /**
     * \return Second centered moment of the underlying distribution,
     *         the covariance
     *
     * \f$ \Sigma =
     *     \sum\limits_i (x_i - \mu)(x_i - \mu)^T \f$
     */
    virtual const SecondMoment& covariance() const = 0;

    /**
     * \copydoc ApproximateMoments::approximate_mean
     */
    virtual const Variate& approximate_mean() const
    {
        return mean();
    }

    /**
     * \copydoc ApproximateMoments::approximate_covariance
     */
    virtual const SecondMoment& approximate_covariance() const
    {
        return covariance();
    }
};

/**
 * \ingroup distribution_interfaces
 */
template <typename Variate>
class Moments<Variate>
    : public Moments<Variate, typename SecondMomentOf<Variate>::Type>
{
public:
    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }
};

/**
 * \ingroup distribution_interfaces
 */
template <>
class Moments<Real>
    : public Moments<Real, Real>
{
public:
    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }
};

}

#endif
<commit_msg>added Doxygen workaround for template specialization<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file moments.hpp
 * \date May 2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__DISTRIBUTION__INTERFACE__MOMENTS_HPP
#define FL__DISTRIBUTION__INTERFACE__MOMENTS_HPP

#include <fl/util/types.hpp>
#include <fl/util/traits.hpp>
#include <fl/distribution/interface/approximate_moments.hpp>

namespace fl
{

#ifndef GENERATING_DOCUMENTATION
// Forward declaration
template <typename...> class Moments;
#endif

/**
 * \ingroup distribution_interfaces
 *
 * \brief Represents the interface providing the first two moments
 *
 * \tparam Variate        Random variable type. This is equivalent to the first
 *                        moment type.
 * \tparam SecondMoment   Second moment type. The second moment is either
 *                        the second uncentered moment \f$Var(X) + X^2\f$ or
 *                        simply the second central moment, the variance or
 *                        covariance \f$Var(X) = Cov(X, X)\f$. Both have the
 *                        same type \c SecondMoment.
 *
 *
 * The Moments interface provides access to the exact first moments of
 * a distribution. The moments represent a subset of the approximate moments.
 */
template <typename Variate_, typename SecondMoment_>
#ifndef GENERATING_DOCUMENTATION
class Moments<Variate_, SecondMoment_>
#else
class Moments
#endif
    : public ApproximateMoments<Variate_, SecondMoment_>
{
public:
    /**
     * \brief Variate Random variable type. This is equivalent to the first
     *        moment type.
     */
    typedef Variate_ Variate;

    /**
     * \brief Second central moment type (e.g. Variance or the Covariance)
     */
    typedef SecondMoment_ SecondMoment;

    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }

    /**
     * \return First moment of the underlying distribution, the mean
     *
     * \f$ \mu = \sum\limits_i x_i p(x_i)\f$
     */
    virtual const Variate& mean() const = 0;

    /**
     * \return Second centered moment of the underlying distribution,
     *         the covariance
     *
     * \f$ \Sigma =
     *     \sum\limits_i (x_i - \mu)(x_i - \mu)^T \f$
     */
    virtual const SecondMoment& covariance() const = 0;

    /**
     * \copydoc ApproximateMoments::approximate_mean
     */
    virtual const Variate& approximate_mean() const
    {
        return mean();
    }

    /**
     * \copydoc ApproximateMoments::approximate_covariance
     */
    virtual const SecondMoment& approximate_covariance() const
    {
        return covariance();
    }
};

/**
 * \ingroup distribution_interfaces
 *
 */
template <typename Variate>
class Moments<Variate>
    : public Moments<Variate, typename SecondMomentOf<Variate>::Type>
{
public:
    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }
};

/**
 * \ingroup distribution_interfaces
 *
 */
template < >
class Moments<Real>
    : public Moments<Real, Real>
{
public:
    /**
     * \brief Overridable default destructor
     */
    virtual ~Moments() { }
};

}

#endif
<|endoftext|>


<commit_before>namespace mant {
  template <typename ParameterType>
  // TODO Add random translation, ... xy methods
  class OptimisationProblem : public Printable {
    public:
      const unsigned int numberOfDimensions_;

      explicit OptimisationProblem(
        const unsigned int& numberOfDimensions) noexcept;

      void setLowerBounds(
        const arma::Col<ParameterType> lowerBounds);

      void setUpperBounds(
        const arma::Col<ParameterType> upperBounds);

      arma::Col<ParameterType> getLowerBounds() const noexcept;

      arma::Col<ParameterType> getUpperBounds() const noexcept;

      double getSoftConstraintsValue(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingLowerBounds(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingUpperBounds(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingSoftConstraints(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingConstraints(
        const arma::Col<ParameterType>& parameter);

      void setParameterPermutation(
          const arma::Col<unsigned int> parameterPermutation);

      void setParameterTranslation(
          const arma::Col<double> parameterTranslation);

      void setParameterScaling(
        const arma::Col<double> parameterScaling);

      void setParameterRotation(
        const arma::Mat<double> parameterRotation);

      void setObjectiveValueTranslation(
        const double objectiveValueTranslation) noexcept;

      void setObjectiveValueScaling(
        const double objectiveValueScaling) noexcept;

      void setAcceptableObjectiveValue(
          const double acceptableObjectiveValue) noexcept;

      double getAcceptableObjectiveValue() const noexcept;

      double getObjectiveValue(
        const arma::Col<ParameterType>& parameter);

      unsigned int getNumberOfEvaluations() const noexcept;

      unsigned int getNumberOfDistinctEvaluations() const noexcept;

      void reset() noexcept;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> getCachedObjectiveValues() const noexcept;

      virtual ~OptimisationProblem() = default;

    protected:
      arma::Col<ParameterType> lowerBounds_;
      arma::Col<ParameterType> upperBounds_;

      arma::Col<unsigned int> parameterPermutation_;
      arma::Col<double> parameterTranslation_;
      arma::Col<double> parameterScaling_;
      arma::Mat<double> parameterRotation_;

      double objectiveValueTranslation_;
      double objectiveValueScaling_;

      double acceptableObjectiveValue_;

      unsigned int numberOfEvaluations_;
      unsigned int numberOfDistinctEvaluations_;

      arma::Col<ParameterType> getDiversifiedParameter(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getSoftConstraintsValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getObjectiveValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept = 0;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> cachedObjectiveValues_;

 #if defined(MANTELLA_USE_PARALLEL)
      friend class cereal::access;
      OptimisationProblem() = default;

      template <typename Archive>
      void serialize(
          Archive& archive) noexcept {
        archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));
        archive(cereal::make_nvp("lowerBounds", lowerBounds_));
        archive(cereal::make_nvp("upperBounds", upperBounds_));
        archive(cereal::make_nvp("parameterTranslation", parameterTranslation_));
        archive(cereal::make_nvp("parameterRotation", parameterRotation_));
        archive(cereal::make_nvp("parameterScaling", parameterScaling_));
        archive(cereal::make_nvp("objectiveValueTranslation", objectiveValueTranslation_));
        archive(cereal::make_nvp("objectiveValueScaling", objectiveValueScaling_));
        archive(cereal::make_nvp("acceptableObjectiveValue", acceptableObjectiveValue_));
      }
#endif
  };

  //
  // Implementation
  //

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept;

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation);

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation);

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling);

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getDiversifiedParameter(
      const arma::Col<double>& parameter) const noexcept;

  template <typename ParameterType>
  OptimisationProblem<ParameterType>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) - std::numeric_limits<ParameterType>::max());
    setUpperBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) + std::numeric_limits<ParameterType>::max());
    setParameterPermutation(arma::linspace<arma::Col<unsigned int>>(0, numberOfDimensions_ - 1, numberOfDimensions));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScaling(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) - std::numeric_limits<double>::max());
    setUpperBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) + std::numeric_limits<double>::max());
    setParameterPermutation(arma::linspace<arma::Col<unsigned int>>(0, numberOfDimensions_ - 1, numberOfDimensions));
    setParameterTranslation(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setParameterRotation(arma::eye<arma::Mat<double>>(numberOfDimensions_, numberOfDimensions_));
    setParameterScaling(arma::ones<arma::Col<double>>(numberOfDimensions_));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScaling(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingLowerBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter >= lowerBounds_);
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingUpperBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter <= upperBounds_);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingSoftConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (getSoftConstraintsValue(parameter) == 0);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (arma::all(isSatisfyingLowerBounds(parameter)) && arma::all(isSatisfyingUpperBounds(parameter)) && isSatisfyingSoftConstraints(parameter));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return objectiveValueScaling_ * getSoftConstraintsValueImplementation(parameter);
  }

  template <typename ParameterType>
  inline double OptimisationProblem<ParameterType>::getObjectiveValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    // Always increase the number of evaluations (whether its computed or retrived from cache).
    ++numberOfEvaluations_;

    // Check if the result is already cached.
    const auto& cachePosition = cachedObjectiveValues_.find(parameter);
    if (cachePosition == cachedObjectiveValues_.cend()) {
      // Increase the number of distinct evaluations only if we actually compute the value.
      ++numberOfDistinctEvaluations_;

      // The result was not found, compute it.
      const double& result = objectiveValueScaling_ * getObjectiveValueImplementation(getDiversifiedParameter(parameter)) + objectiveValueTranslation_;
      cachedObjectiveValues_.insert({parameter, result});
      return result;
    } else {
      // Return the found result.
      return cachePosition->second;
    }
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getLowerBounds() const noexcept {
    return lowerBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setLowerBounds(
      const arma::Col<ParameterType> lowerBounds) {
    checkDimensionCompatible("The number of elements", lowerBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    lowerBounds_ = lowerBounds;
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getUpperBounds() const noexcept {
    return upperBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setUpperBounds(
      const arma::Col<ParameterType> upperBounds) {
    checkDimensionCompatible("The number of elements", upperBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    upperBounds_ = upperBounds;
  }

  template <typename ParameterType>
  inline void OptimisationProblem<ParameterType>::setParameterPermutation(
      const arma::Col<unsigned int> parameterPermutation) {
    // TODO Check if this is actually a permutaion
    checkDimensionCompatible("The number of elements", parameterPermutation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterPermutation_ = parameterPermutation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation) {
    checkDimensionCompatible("The number of elements", parameterTranslation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterTranslation_ = parameterTranslation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation) {
    checkDimensionCompatible("The number of rows", parameterRotation.n_rows, "the number of dimensions", numberOfDimensions_);
    checkRotationMatrix("The matrix", parameterRotation);

    parameterRotation_ = parameterRotation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling) {
    checkDimensionCompatible("The number of elements", parameterScaling.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterScaling_ = parameterScaling;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setObjectiveValueTranslation(
      const double objectiveValueTranslation) noexcept {
    objectiveValueTranslation_ = objectiveValueTranslation;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::OptimisationProblem::setObjectiveValueScaling(
      const double objectiveValueScaling) noexcept {
    objectiveValueScaling_ = objectiveValueScaling;
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getAcceptableObjectiveValue() const noexcept {
    return acceptableObjectiveValue_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setAcceptableObjectiveValue(
      const double acceptableObjectiveValue) noexcept {
    acceptableObjectiveValue_ = acceptableObjectiveValue;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfEvaluations() const noexcept {
    return numberOfEvaluations_;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfDistinctEvaluations() const noexcept {
    return numberOfDistinctEvaluations_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::reset() noexcept {
    numberOfEvaluations_ = 0;
    numberOfDistinctEvaluations_ = 0;

    cachedObjectiveValues_.clear();
  }

  template <typename ParameterType>
  std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> OptimisationProblem<ParameterType>::getCachedObjectiveValues() const noexcept {
    return cachedObjectiveValues_;
  }

  template <typename ParameterType>
  inline arma::Col<ParameterType> OptimisationProblem<ParameterType>::getDiversifiedParameter(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameter.elem(parameterPermutation_);
  }

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getDiversifiedParameter(
      const arma::Col<double>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameterRotation_ * (parameterScaling_ % parameter.elem(parameterPermutation_) - parameterTranslation_);
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValueImplementation(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return 0.0;
  }
}
<commit_msg>Removed completed ToDo [ci skip]<commit_after>namespace mant {
  template <typename ParameterType>
  class OptimisationProblem : public Printable {
    public:
      const unsigned int numberOfDimensions_;

      explicit OptimisationProblem(
        const unsigned int& numberOfDimensions) noexcept;

      void setLowerBounds(
        const arma::Col<ParameterType> lowerBounds);

      void setUpperBounds(
        const arma::Col<ParameterType> upperBounds);

      arma::Col<ParameterType> getLowerBounds() const noexcept;

      arma::Col<ParameterType> getUpperBounds() const noexcept;

      double getSoftConstraintsValue(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingLowerBounds(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingUpperBounds(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingSoftConstraints(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingConstraints(
        const arma::Col<ParameterType>& parameter);

      void setParameterPermutation(
          const arma::Col<unsigned int> parameterPermutation);

      void setParameterTranslation(
          const arma::Col<double> parameterTranslation);

      void setParameterScaling(
        const arma::Col<double> parameterScaling);

      void setParameterRotation(
        const arma::Mat<double> parameterRotation);

      void setObjectiveValueTranslation(
        const double objectiveValueTranslation) noexcept;

      void setObjectiveValueScaling(
        const double objectiveValueScaling) noexcept;

      void setAcceptableObjectiveValue(
          const double acceptableObjectiveValue) noexcept;

      double getAcceptableObjectiveValue() const noexcept;

      double getObjectiveValue(
        const arma::Col<ParameterType>& parameter);

      unsigned int getNumberOfEvaluations() const noexcept;

      unsigned int getNumberOfDistinctEvaluations() const noexcept;

      void reset() noexcept;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> getCachedObjectiveValues() const noexcept;

      virtual ~OptimisationProblem() = default;

    protected:
      arma::Col<ParameterType> lowerBounds_;
      arma::Col<ParameterType> upperBounds_;

      arma::Col<unsigned int> parameterPermutation_;
      arma::Col<double> parameterTranslation_;
      arma::Col<double> parameterScaling_;
      arma::Mat<double> parameterRotation_;

      double objectiveValueTranslation_;
      double objectiveValueScaling_;

      double acceptableObjectiveValue_;

      unsigned int numberOfEvaluations_;
      unsigned int numberOfDistinctEvaluations_;

      arma::Col<ParameterType> getDiversifiedParameter(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getSoftConstraintsValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getObjectiveValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept = 0;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> cachedObjectiveValues_;

 #if defined(MANTELLA_USE_PARALLEL)
      friend class cereal::access;
      OptimisationProblem() = default;

      template <typename Archive>
      void serialize(
          Archive& archive) noexcept {
        archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));
        archive(cereal::make_nvp("lowerBounds", lowerBounds_));
        archive(cereal::make_nvp("upperBounds", upperBounds_));
        archive(cereal::make_nvp("parameterTranslation", parameterTranslation_));
        archive(cereal::make_nvp("parameterRotation", parameterRotation_));
        archive(cereal::make_nvp("parameterScaling", parameterScaling_));
        archive(cereal::make_nvp("objectiveValueTranslation", objectiveValueTranslation_));
        archive(cereal::make_nvp("objectiveValueScaling", objectiveValueScaling_));
        archive(cereal::make_nvp("acceptableObjectiveValue", acceptableObjectiveValue_));
      }
#endif
  };

  //
  // Implementation
  //

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept;

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation);

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation);

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling);

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getDiversifiedParameter(
      const arma::Col<double>& parameter) const noexcept;

  template <typename ParameterType>
  OptimisationProblem<ParameterType>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) - std::numeric_limits<ParameterType>::max());
    setUpperBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) + std::numeric_limits<ParameterType>::max());
    setParameterPermutation(arma::linspace<arma::Col<unsigned int>>(0, numberOfDimensions_ - 1, numberOfDimensions));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScaling(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) - std::numeric_limits<double>::max());
    setUpperBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) + std::numeric_limits<double>::max());
    setParameterPermutation(arma::linspace<arma::Col<unsigned int>>(0, numberOfDimensions_ - 1, numberOfDimensions));
    setParameterTranslation(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setParameterRotation(arma::eye<arma::Mat<double>>(numberOfDimensions_, numberOfDimensions_));
    setParameterScaling(arma::ones<arma::Col<double>>(numberOfDimensions_));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScaling(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingLowerBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter >= lowerBounds_);
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingUpperBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter <= upperBounds_);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingSoftConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (getSoftConstraintsValue(parameter) == 0);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (arma::all(isSatisfyingLowerBounds(parameter)) && arma::all(isSatisfyingUpperBounds(parameter)) && isSatisfyingSoftConstraints(parameter));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return objectiveValueScaling_ * getSoftConstraintsValueImplementation(parameter);
  }

  template <typename ParameterType>
  inline double OptimisationProblem<ParameterType>::getObjectiveValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    // Always increase the number of evaluations (whether its computed or retrived from cache).
    ++numberOfEvaluations_;

    // Check if the result is already cached.
    const auto& cachePosition = cachedObjectiveValues_.find(parameter);
    if (cachePosition == cachedObjectiveValues_.cend()) {
      // Increase the number of distinct evaluations only if we actually compute the value.
      ++numberOfDistinctEvaluations_;

      // The result was not found, compute it.
      const double& result = objectiveValueScaling_ * getObjectiveValueImplementation(getDiversifiedParameter(parameter)) + objectiveValueTranslation_;
      cachedObjectiveValues_.insert({parameter, result});
      return result;
    } else {
      // Return the found result.
      return cachePosition->second;
    }
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getLowerBounds() const noexcept {
    return lowerBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setLowerBounds(
      const arma::Col<ParameterType> lowerBounds) {
    checkDimensionCompatible("The number of elements", lowerBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    lowerBounds_ = lowerBounds;
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getUpperBounds() const noexcept {
    return upperBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setUpperBounds(
      const arma::Col<ParameterType> upperBounds) {
    checkDimensionCompatible("The number of elements", upperBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    upperBounds_ = upperBounds;
  }

  template <typename ParameterType>
  inline void OptimisationProblem<ParameterType>::setParameterPermutation(
      const arma::Col<unsigned int> parameterPermutation) {
    // TODO Check if this is actually a permutaion
    checkDimensionCompatible("The number of elements", parameterPermutation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterPermutation_ = parameterPermutation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation) {
    checkDimensionCompatible("The number of elements", parameterTranslation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterTranslation_ = parameterTranslation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation) {
    checkDimensionCompatible("The number of rows", parameterRotation.n_rows, "the number of dimensions", numberOfDimensions_);
    checkRotationMatrix("The matrix", parameterRotation);

    parameterRotation_ = parameterRotation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling) {
    checkDimensionCompatible("The number of elements", parameterScaling.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterScaling_ = parameterScaling;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setObjectiveValueTranslation(
      const double objectiveValueTranslation) noexcept {
    objectiveValueTranslation_ = objectiveValueTranslation;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::OptimisationProblem::setObjectiveValueScaling(
      const double objectiveValueScaling) noexcept {
    objectiveValueScaling_ = objectiveValueScaling;
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getAcceptableObjectiveValue() const noexcept {
    return acceptableObjectiveValue_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setAcceptableObjectiveValue(
      const double acceptableObjectiveValue) noexcept {
    acceptableObjectiveValue_ = acceptableObjectiveValue;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfEvaluations() const noexcept {
    return numberOfEvaluations_;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfDistinctEvaluations() const noexcept {
    return numberOfDistinctEvaluations_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::reset() noexcept {
    numberOfEvaluations_ = 0;
    numberOfDistinctEvaluations_ = 0;

    cachedObjectiveValues_.clear();
  }

  template <typename ParameterType>
  std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> OptimisationProblem<ParameterType>::getCachedObjectiveValues() const noexcept {
    return cachedObjectiveValues_;
  }

  template <typename ParameterType>
  inline arma::Col<ParameterType> OptimisationProblem<ParameterType>::getDiversifiedParameter(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameter.elem(parameterPermutation_);
  }

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getDiversifiedParameter(
      const arma::Col<double>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameterRotation_ * (parameterScaling_ % parameter.elem(parameterPermutation_) - parameterTranslation_);
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValueImplementation(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return 0.0;
  }
}
<|endoftext|>


<commit_before>namespace mant {
  template <typename ParameterType>
  class OptimisationProblem : public Printable {
    public:
      const unsigned int numberOfDimensions_;

      explicit OptimisationProblem(
        const unsigned int& numberOfDimensions) noexcept;

      void setLowerBounds(
        const arma::Col<ParameterType> lowerBounds);

      void setUpperBounds(
        const arma::Col<ParameterType> upperBounds);

      arma::Col<ParameterType> getLowerBounds() const noexcept;

      arma::Col<ParameterType> getUpperBounds() const noexcept;

      double getSoftConstraintsValue(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingLowerBounds(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingUpperBounds(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingSoftConstraints(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingConstraints(
        const arma::Col<ParameterType>& parameter);

      void setParameterTranslation(
          const arma::Col<ParameterType> parameterTranslation);

      void setParameterScale(
        const arma::Col<ParameterType> parameterScale);

      void setParameterRotation(
        const arma::Mat<ParameterType> parameterRotation);

      void setObjectiveValueTranslation(
        const double objectiveValueTranslation) noexcept;

      void setObjectiveValueScale(
        const double objectiveValueScale) noexcept;

      void setAcceptableObjectiveValue(
          const double acceptableObjectiveValue) noexcept;

      double getAcceptableObjectiveValue() const noexcept;

      double getObjectiveValue(
        const arma::Col<ParameterType>& parameter);

      unsigned int getNumberOfEvaluations() const noexcept;

      unsigned int getNumberOfDistinctEvaluations() const noexcept;

      void reset() noexcept;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> getCachedObjectiveValues() const noexcept;

      virtual ~OptimisationProblem() = default;

    protected:
      arma::Col<ParameterType> lowerBounds_;
      arma::Col<ParameterType> upperBounds_;

      arma::Col<double> parameterTranslation_;
      arma::Col<double> parameterScale_;
      arma::Mat<double> parameterRotation_;

      double objectiveValueTranslation_;
      double objectiveValueScale_;

      double acceptableObjectiveValue_;

      unsigned int numberOfEvaluations_;
      unsigned int numberOfDistinctEvaluations_;

      arma::Col<ParameterType> getScaledCongruentParameter(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getSoftConstraintsValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getObjectiveValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept = 0;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> cachedObjectiveValues_;

 #if defined(MANTELLA_USE_PARALLEL)
      friend class cereal::access;
      OptimisationProblem() = default;

      template <typename Archive>
      void serialize(
          Archive& archive) noexcept {
        archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));
        archive(cereal::make_nvp("lowerBounds", lowerBounds_));
        archive(cereal::make_nvp("upperBounds", upperBounds_));
        archive(cereal::make_nvp("parameterTranslation", parameterTranslation_));
        archive(cereal::make_nvp("parameterRotation", parameterRotation_));
        archive(cereal::make_nvp("parameterScale", parameterScale_));
        archive(cereal::make_nvp("objectiveValueTranslation", objectiveValueTranslation_));
        archive(cereal::make_nvp("objectiveValueScale", objectiveValueScale_));
        archive(cereal::make_nvp("acceptableObjectiveValue", acceptableObjectiveValue_));
      }
#endif
  };

  //
  // Implementation
  //

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept;

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation);

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation);

  template <>
  inline void OptimisationProblem<double>::setParameterScale(
      const arma::Col<double> parameterScale);

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getScaledCongruentParameter(
      const arma::Col<double>& parameter) const noexcept;

  template <typename ParameterType>
  OptimisationProblem<ParameterType>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) - std::numeric_limits<ParameterType>::max());
    setUpperBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) + std::numeric_limits<ParameterType>::max());
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScale(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) - std::numeric_limits<double>::max());
    setUpperBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) + std::numeric_limits<double>::max());
    setParameterTranslation(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setParameterRotation(arma::eye<arma::Mat<double>>(numberOfDimensions_, numberOfDimensions_));
    setParameterScale(arma::ones<arma::Col<double>>(numberOfDimensions_));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScale(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingLowerBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter >= lowerBounds_);
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingUpperBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter <= upperBounds_);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingSoftConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (getSoftConstraintsValue(parameter) == 0);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (arma::all(isSatisfyingLowerBounds(parameter)) && arma::all(isSatisfyingUpperBounds(parameter)) && isSatisfyingSoftConstraints(parameter));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return getSoftConstraintsValueImplementation(parameter);
  }

  template <typename ParameterType>
  inline double OptimisationProblem<ParameterType>::getObjectiveValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    // Always increase the number of evaluations (whether its computed or retrived from cache).
    ++numberOfEvaluations_;

    // Check if the result is already cached.
    const auto& cachePosition = cachedObjectiveValues_.find(parameter);
    if (cachePosition == cachedObjectiveValues_.cend()) {
      // Increase the number of distinct evaluations only if we actually compute the value.
      ++numberOfDistinctEvaluations_;

      // The result was not found, compute it.
      const double& result = objectiveValueScale_ * getObjectiveValueImplementation(getScaledCongruentParameter(parameter)) + objectiveValueTranslation_;
      cachedObjectiveValues_.insert({parameter, result});
      return result;
    } else {
      // Return the found result.
      return cachePosition->second;
    }
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getLowerBounds() const noexcept {
    return lowerBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setLowerBounds(
      const arma::Col<ParameterType> lowerBounds) {
    checkDimensionCompatible("The number of elements", lowerBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    lowerBounds_ = lowerBounds;
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getUpperBounds() const noexcept {
    return upperBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setUpperBounds(
      const arma::Col<ParameterType> upperBounds) {
    checkDimensionCompatible("The number of elements", upperBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    upperBounds_ = upperBounds;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation) {
    checkDimensionCompatible("The number of elements", parameterTranslation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterTranslation_ = parameterTranslation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation) {
    checkDimensionCompatible("The number of rows", parameterRotation.n_rows, "the number of dimensions", numberOfDimensions_);
    checkRotationMatrix("The matrix", parameterRotation);

    parameterRotation_ = parameterRotation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterScale(
      const arma::Col<double> parameterScale) {
    checkDimensionCompatible("The number of elements", parameterScale.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterScale_ = parameterScale;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setObjectiveValueTranslation(
      const double objectiveValueTranslation) noexcept {
    objectiveValueTranslation_ = objectiveValueTranslation;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::OptimisationProblem::setObjectiveValueScale(
      const double objectiveValueScale) noexcept {
    objectiveValueScale_ = objectiveValueScale;
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getAcceptableObjectiveValue() const noexcept {
    return acceptableObjectiveValue_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setAcceptableObjectiveValue(
      const double acceptableObjectiveValue) noexcept {
    acceptableObjectiveValue_ = acceptableObjectiveValue;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfEvaluations() const noexcept {
    return numberOfEvaluations_;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfDistinctEvaluations() const noexcept {
    return numberOfDistinctEvaluations_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::reset() noexcept {
    numberOfEvaluations_ = 0;
    numberOfDistinctEvaluations_ = 0;

    cachedObjectiveValues_.clear();
  }

  template <typename ParameterType>
  std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> OptimisationProblem<ParameterType>::getCachedObjectiveValues() const noexcept {
    return cachedObjectiveValues_;
  }

  template <typename ParameterType>
  inline arma::Col<ParameterType> OptimisationProblem<ParameterType>::getScaledCongruentParameter(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameter;
  }

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getScaledCongruentParameter(
      const arma::Col<double>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameterRotation_ * (parameter + (parameterScale_ % parameterTranslation_));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValueImplementation(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return 0.0;
  }
}
<commit_msg>Renamed ParameterScale to ParameterScaling<commit_after>namespace mant {
  template <typename ParameterType>
  class OptimisationProblem : public Printable {
    public:
      const unsigned int numberOfDimensions_;

      explicit OptimisationProblem(
        const unsigned int& numberOfDimensions) noexcept;

      void setLowerBounds(
        const arma::Col<ParameterType> lowerBounds);

      void setUpperBounds(
        const arma::Col<ParameterType> upperBounds);

      arma::Col<ParameterType> getLowerBounds() const noexcept;

      arma::Col<ParameterType> getUpperBounds() const noexcept;

      double getSoftConstraintsValue(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingLowerBounds(
        const arma::Col<ParameterType>& parameter);

      arma::Col<unsigned int> isSatisfyingUpperBounds(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingSoftConstraints(
        const arma::Col<ParameterType>& parameter);

      bool isSatisfyingConstraints(
        const arma::Col<ParameterType>& parameter);

      void setParameterTranslation(
          const arma::Col<ParameterType> parameterTranslation);

      void setParameterScaling(
        const arma::Col<ParameterType> parameterScaling);

      void setParameterRotation(
        const arma::Mat<ParameterType> parameterRotation);

      void setObjectiveValueTranslation(
        const double objectiveValueTranslation) noexcept;

      void setObjectiveValueScale(
        const double objectiveValueScale) noexcept;

      void setAcceptableObjectiveValue(
          const double acceptableObjectiveValue) noexcept;

      double getAcceptableObjectiveValue() const noexcept;

      double getObjectiveValue(
        const arma::Col<ParameterType>& parameter);

      unsigned int getNumberOfEvaluations() const noexcept;

      unsigned int getNumberOfDistinctEvaluations() const noexcept;

      void reset() noexcept;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> getCachedObjectiveValues() const noexcept;

      virtual ~OptimisationProblem() = default;

    protected:
      arma::Col<ParameterType> lowerBounds_;
      arma::Col<ParameterType> upperBounds_;

      arma::Col<double> parameterTranslation_;
      arma::Col<double> parameterScaling_;
      arma::Mat<double> parameterRotation_;

      double objectiveValueTranslation_;
      double objectiveValueScale_;

      double acceptableObjectiveValue_;

      unsigned int numberOfEvaluations_;
      unsigned int numberOfDistinctEvaluations_;

      arma::Col<ParameterType> getScaledCongruentParameter(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getSoftConstraintsValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept;

      virtual double getObjectiveValueImplementation(
        const arma::Col<ParameterType>& parameter) const noexcept = 0;

      std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> cachedObjectiveValues_;

 #if defined(MANTELLA_USE_PARALLEL)
      friend class cereal::access;
      OptimisationProblem() = default;

      template <typename Archive>
      void serialize(
          Archive& archive) noexcept {
        archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));
        archive(cereal::make_nvp("lowerBounds", lowerBounds_));
        archive(cereal::make_nvp("upperBounds", upperBounds_));
        archive(cereal::make_nvp("parameterTranslation", parameterTranslation_));
        archive(cereal::make_nvp("parameterRotation", parameterRotation_));
        archive(cereal::make_nvp("parameterScaling", parameterScaling_));
        archive(cereal::make_nvp("objectiveValueTranslation", objectiveValueTranslation_));
        archive(cereal::make_nvp("objectiveValueScale", objectiveValueScale_));
        archive(cereal::make_nvp("acceptableObjectiveValue", acceptableObjectiveValue_));
      }
#endif
  };

  //
  // Implementation
  //

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept;

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation);

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation);

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling);

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getScaledCongruentParameter(
      const arma::Col<double>& parameter) const noexcept;

  template <typename ParameterType>
  OptimisationProblem<ParameterType>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) - std::numeric_limits<ParameterType>::max());
    setUpperBounds(arma::zeros<arma::Col<ParameterType>>(numberOfDimensions_) + std::numeric_limits<ParameterType>::max());
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScale(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <>
  inline OptimisationProblem<double>::OptimisationProblem(
      const unsigned int& numberOfDimensions) noexcept
    : numberOfDimensions_(numberOfDimensions),
      numberOfEvaluations_(0),
      numberOfDistinctEvaluations_(0) {
    setLowerBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) - std::numeric_limits<double>::max());
    setUpperBounds(arma::zeros<arma::Col<double>>(numberOfDimensions_) + std::numeric_limits<double>::max());
    setParameterTranslation(arma::zeros<arma::Col<double>>(numberOfDimensions_));
    setParameterRotation(arma::eye<arma::Mat<double>>(numberOfDimensions_, numberOfDimensions_));
    setParameterScaling(arma::ones<arma::Col<double>>(numberOfDimensions_));
    setObjectiveValueTranslation(0.0);
    setObjectiveValueScale(1.0);
    setAcceptableObjectiveValue(std::numeric_limits<double>::lowest());
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingLowerBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter >= lowerBounds_);
  }

  template <typename ParameterType>
  arma::Col<unsigned int> OptimisationProblem<ParameterType>::isSatisfyingUpperBounds(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (parameter <= upperBounds_);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingSoftConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (getSoftConstraintsValue(parameter) == 0);
  }

  template <typename ParameterType>
  bool OptimisationProblem<ParameterType>::isSatisfyingConstraints(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return (arma::all(isSatisfyingLowerBounds(parameter)) && arma::all(isSatisfyingUpperBounds(parameter)) && isSatisfyingSoftConstraints(parameter));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    return getSoftConstraintsValueImplementation(parameter);
  }

  template <typename ParameterType>
  inline double OptimisationProblem<ParameterType>::getObjectiveValue(
      const arma::Col<ParameterType>& parameter) {
    checkDimensionCompatible("The number of elements", parameter.n_elem, "the number of dimensions", numberOfDimensions_);

    // Always increase the number of evaluations (whether its computed or retrived from cache).
    ++numberOfEvaluations_;

    // Check if the result is already cached.
    const auto& cachePosition = cachedObjectiveValues_.find(parameter);
    if (cachePosition == cachedObjectiveValues_.cend()) {
      // Increase the number of distinct evaluations only if we actually compute the value.
      ++numberOfDistinctEvaluations_;

      // The result was not found, compute it.
      const double& result = objectiveValueScale_ * getObjectiveValueImplementation(getScaledCongruentParameter(parameter)) + objectiveValueTranslation_;
      cachedObjectiveValues_.insert({parameter, result});
      return result;
    } else {
      // Return the found result.
      return cachePosition->second;
    }
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getLowerBounds() const noexcept {
    return lowerBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setLowerBounds(
      const arma::Col<ParameterType> lowerBounds) {
    checkDimensionCompatible("The number of elements", lowerBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    lowerBounds_ = lowerBounds;
  }

  template <typename ParameterType>
  arma::Col<ParameterType> OptimisationProblem<ParameterType>::getUpperBounds() const noexcept {
    return upperBounds_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setUpperBounds(
      const arma::Col<ParameterType> upperBounds) {
    checkDimensionCompatible("The number of elements", upperBounds.n_elem, "the number of dimensions", numberOfDimensions_);

    upperBounds_ = upperBounds;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterTranslation(
      const arma::Col<double> parameterTranslation) {
    checkDimensionCompatible("The number of elements", parameterTranslation.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterTranslation_ = parameterTranslation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterRotation(
      const arma::Mat<double> parameterRotation) {
    checkDimensionCompatible("The number of rows", parameterRotation.n_rows, "the number of dimensions", numberOfDimensions_);
    checkRotationMatrix("The matrix", parameterRotation);

    parameterRotation_ = parameterRotation;
  }

  template <>
  inline void OptimisationProblem<double>::setParameterScaling(
      const arma::Col<double> parameterScaling) {
    checkDimensionCompatible("The number of elements", parameterScaling.n_elem, "the number of dimensions", numberOfDimensions_);

    parameterScaling_ = parameterScaling;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setObjectiveValueTranslation(
      const double objectiveValueTranslation) noexcept {
    objectiveValueTranslation_ = objectiveValueTranslation;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::OptimisationProblem::setObjectiveValueScale(
      const double objectiveValueScale) noexcept {
    objectiveValueScale_ = objectiveValueScale;
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getAcceptableObjectiveValue() const noexcept {
    return acceptableObjectiveValue_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::setAcceptableObjectiveValue(
      const double acceptableObjectiveValue) noexcept {
    acceptableObjectiveValue_ = acceptableObjectiveValue;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfEvaluations() const noexcept {
    return numberOfEvaluations_;
  }

  template <typename ParameterType>
  unsigned int OptimisationProblem<ParameterType>::getNumberOfDistinctEvaluations() const noexcept {
    return numberOfDistinctEvaluations_;
  }

  template <typename ParameterType>
  void OptimisationProblem<ParameterType>::reset() noexcept {
    numberOfEvaluations_ = 0;
    numberOfDistinctEvaluations_ = 0;

    cachedObjectiveValues_.clear();
  }

  template <typename ParameterType>
  std::unordered_map<arma::Col<ParameterType>, double, Hash, IsEqual> OptimisationProblem<ParameterType>::getCachedObjectiveValues() const noexcept {
    return cachedObjectiveValues_;
  }

  template <typename ParameterType>
  inline arma::Col<ParameterType> OptimisationProblem<ParameterType>::getScaledCongruentParameter(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameter;
  }

  template <>
  inline arma::Col<double> OptimisationProblem<double>::getScaledCongruentParameter(
      const arma::Col<double>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return parameterRotation_ * (parameter + (parameterScale_ % parameterTranslation_));
  }

  template <typename ParameterType>
  double OptimisationProblem<ParameterType>::getSoftConstraintsValueImplementation(
      const arma::Col<ParameterType>& parameter) const noexcept {
    assert(isDimensionCompatible(parameter.n_elem, numberOfDimensions_));

    return 0.0;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ChromeFrameHost implementation.
#include "ceee/ie/common/chrome_frame_host.h"

#include <algorithm>
#include <vector>

#include "base/logging.h"
#include "ceee/common/com_utils.h"
#include "ceee/common/process_utils_win.h"
#include "ceee/ie/common/ceee_module_util.h"
#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/common/chrome_switches.h"

#include "toolband.h"  // NOLINT

namespace ext = extension_automation_constants;

_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_ =
    { CC_STDCALL, VT_EMPTY, 1, { VT_DISPATCH } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_long_ =
    { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_bstr_ =
    { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_BSTR } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_variantptr_ =
    { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_BYREF | VT_VARIANT } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_bstr_i4_=
    { CC_STDCALL, VT_EMPTY, 2, { VT_BSTR, VT_I4 } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_bstrarray_=
    { CC_STDCALL, VT_EMPTY, 1, { VT_ARRAY | VT_BSTR } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_void_=
    { CC_STDCALL, VT_EMPTY, 0, { } };

// {AFA3E2CF-2C8E-4546-8CD0-A2D93759A4DE}
extern const GUID IID_IChromeFrameHost =
  { 0xafa3e2cf, 0x2c8e, 0x4546,
      { 0x8c, 0xd0, 0xa2, 0xd9, 0x37, 0x59, 0xa4, 0xde } };

ChromeFrameHost::ChromeFrameHost()
    : document_loaded_(false), origin_(ext::kAutomationOrigin) {
  LOG(INFO) << "Create ChromeFrameHost(" << this << ")";
}

ChromeFrameHost::~ChromeFrameHost() {
  LOG(INFO) << "Destroy ChromeFrameHost(" << this << ")";
}

HRESULT ChromeFrameHost::FinalConstruct() {
  return S_OK;
}

void ChromeFrameHost::FinalRelease() {
}

STDMETHODIMP ChromeFrameHost::GetWantsPrivileged(boolean* wants_privileged) {
  *wants_privileged = true;
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::GetChromeExtraArguments(BSTR* args) {
  DCHECK(args);

  // Extra arguments are passed on verbatim, so we add the -- prefix.
  CComBSTR str = "--";
  str.Append(switches::kEnableExperimentalExtensionApis);

  *args = str.Detach();
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::GetChromeProfileName(BSTR* profile_name) {
  return chrome_profile_name_.CopyTo(profile_name);
}

STDMETHODIMP ChromeFrameHost::GetExtensionApisToAutomate(
    BSTR* functions_enabled) {
  DCHECK(functions_enabled != NULL);
  HRESULT hr = S_FALSE;
  if (event_sink_ != NULL) {
    hr = event_sink_->OnCfGetExtensionApisToAutomate(functions_enabled);
#ifndef NDEBUG
    if (*functions_enabled != NULL) {
      // Only one chrome frame host is allowed to return a list of functions
      // to enable automation on, so make sure we are the one and only.
      std::wstring event_name(L"google-ceee-apiautomation!");

      DCHECK(chrome_profile_name_ != NULL);
      if (chrome_profile_name_ != NULL)
        event_name += chrome_profile_name_;

      std::replace(event_name.begin(), event_name.end(), '\\', '!');
      std::transform(
          event_name.begin(), event_name.end(), event_name.begin(), tolower);
      automating_extension_api_.Set(
          ::CreateEvent(NULL, TRUE, TRUE, event_name.c_str()));
      DWORD we = ::GetLastError();
      DCHECK(automating_extension_api_ != NULL &&
             we != ERROR_ALREADY_EXISTS &&
             we != ERROR_ACCESS_DENIED);
    }
#endif  // NDEBUG
  }
  return hr;
}

HRESULT ChromeFrameHost::Initialize() {
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::TearDown() {
  if (IsWindow()) {
    // TearDown the ActiveX host window.
    CAxWindow host(m_hWnd);
    CComPtr<IObjectWithSite> host_with_site;
    HRESULT hr = host.QueryHost(&host_with_site);
    if (SUCCEEDED(hr))
      host_with_site->SetSite(NULL);

    DestroyWindow();
  }

  if (chrome_frame_)
    ChromeFrameEvents::DispEventUnadvise(chrome_frame_);

  chrome_frame_.Release();
#ifndef NDEBUG
  automating_extension_api_.Close();
#endif
  return S_OK;
}

STDMETHODIMP_(void) ChromeFrameHost::SetEventSink(
    IChromeFrameHostEvents* event_sink) {
  event_sink_ = event_sink;
}

HRESULT ChromeFrameHost::InstallExtension(BSTR crx_path) {
  if (chrome_frame_) {
    return chrome_frame_->installExtension(crx_path);
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::LoadExtension(BSTR extension_dir) {
  if (chrome_frame_) {
    return chrome_frame_->installExtension(extension_dir);
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::GetEnabledExtensions() {
  if (chrome_frame_) {
    return chrome_frame_->getEnabledExtensions();
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::GetSessionId(int *session_id) {
  if (chrome_frame_) {
    CComQIPtr<IChromeFrameInternal> chrome_frame_internal_(chrome_frame_);
    if (chrome_frame_internal_)
      return chrome_frame_internal_->getSessionId(session_id);
    else
      return kInvalidChromeSessionId;
  }
  NOTREACHED();
  return E_UNEXPECTED;
}

void ChromeFrameHost::OnFinalMessage(HWND window) {
  GetUnknown()->Release();
}

HRESULT ChromeFrameHost::SetChildSite(IUnknown* child) {
  if (child == NULL)
    return E_POINTER;

  HRESULT hr = S_OK;
  CComPtr<IObjectWithSite> child_site;
  hr = child->QueryInterface(&child_site);
  if (SUCCEEDED(hr))
    hr = child_site->SetSite(GetUnknown());

  return hr;
}

LRESULT ChromeFrameHost::OnCreate(LPCREATESTRUCT lpCreateStruct) {
  // Grab a self-reference.
  GetUnknown()->AddRef();

  return 0;
}

HRESULT ChromeFrameHost::SetUrl(BSTR url) {
  HRESULT hr = chrome_frame_->put_src(url);
  DCHECK(SUCCEEDED(hr)) << "Failed to navigate Chrome Frame: " <<
    com::LogHr(hr);
  return hr;
}

STDMETHODIMP ChromeFrameHost::StartChromeFrame() {
  DCHECK(!IsWindow());

  // Create a message window to host our control.
  if (NULL == Create(HWND_MESSAGE))
    return E_FAIL;

  // Create a host window instance.
  CComPtr<IAxWinHostWindow> host;
  HRESULT hr = CreateActiveXHost(&host);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to create ActiveX host window: " << com::LogHr(hr);
    return hr;
  }

  // We're the site for the host window, this needs to be in place
  // before we attach ChromeFrame to the ActiveX control window, so
  // as to allow it to probe our service provider.
  hr = SetChildSite(host);
  DCHECK(SUCCEEDED(hr));

  // Create the chrome frame instance.
  hr = CreateChromeFrame(&chrome_frame_);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed create Chrome Frame: " << com::LogHr(hr);
    return hr;
  }

  // And attach it to our window. This causes the host to subclass
  // our window and attach itself to it.
  hr = host->AttachControl(chrome_frame_, m_hWnd);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to attach Chrome Frame to the host" << com::LogHr(hr);
    return hr;
  }

  // Hook up the chrome frame event listener.
  hr = ChromeFrameEvents::DispEventAdvise(chrome_frame_);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to hook up event sink: " << com::LogHr(hr);
    return hr;
  }

  return hr;
}

HRESULT ChromeFrameHost::CreateActiveXHost(IAxWinHostWindow** host) {
  return CAxHostWindow::CreateInstance(host);
}

HRESULT ChromeFrameHost::CreateChromeFrame(IChromeFrame** chrome_frame) {
  CComPtr<IChromeFrame> new_cf;
  HRESULT hr = new_cf.CoCreateInstance(L"ChromeTab.ChromeFrame");
  if (SUCCEEDED(hr))
    hr = new_cf.CopyTo(chrome_frame);

  return hr;
}

STDMETHODIMP ChromeFrameHost::PostMessage(BSTR message, BSTR target) {
  if (!document_loaded_) {
    PostedMessage posted_message = { message, target };
    posted_messages_.push_back(posted_message);
    return S_FALSE;
  }

  HRESULT hr = chrome_frame_->postPrivateMessage(message, origin_, target);

  return hr;
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfLoad(IDispatch* event) {
  DLOG(INFO) << "OnCfLoad";
  if (document_loaded_) {
    // If we were already loaded, our list should be empty.
    DCHECK(posted_messages_.empty());
    return;
  }
  document_loaded_ = true;

  // Flush all posted messages.
  PostedMessageList::iterator it(posted_messages_.begin());
  for (; it != posted_messages_.end(); ++it) {
    HRESULT hr = chrome_frame_->postPrivateMessage(it->message, origin_,
                                                   it->target);
    DCHECK(SUCCEEDED(hr)) << "postPrivateMessage failed with: " <<
        com::LogHr(hr);
  }
  posted_messages_.clear();
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfLoadError(IDispatch* event) {
  DLOG(ERROR) << "OnCfLoadError";
  DCHECK(false) << "OnCfLoadError";
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfExtensionReady(BSTR path,
                                                        int response) {
  DLOG(INFO) << "OnCfExtensionReady: " << path << ", " << response;
  // Early exit if there's no sink.
  if (event_sink_ == NULL)
    return;
  event_sink_->OnCfExtensionReady(path, response);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfGetEnabledExtensionsComplete(
    SAFEARRAY* extension_directories) {
  DLOG(INFO) << "OnCfGetEnabledExtensionsComplete";
  if (event_sink_)
    event_sink_->OnCfGetEnabledExtensionsComplete(extension_directories);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfChannelError() {
  DCHECK(false) << "OnCfChannelError means that Chrome has Crashed!";
  if (event_sink_)
    event_sink_->OnCfChannelError();
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfMessage(IDispatch* event) {
  DLOG(INFO) << "OnCfMessage";
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfReadyStateChanged(LONG state) {
  DLOG(INFO) << "OnCfReadyStateChanged(" << state << ")";
  if (event_sink_)
    event_sink_->OnCfReadyStateChanged(state);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfPrivateMessage(IDispatch* event,
                                                        BSTR target) {
  // Early exit if there's no sink.
  if (event_sink_ == NULL)
    return;

  // Make sure that the message has a "data" member and get it.  This should
  // be a JSON-encoded command to execute.
  CComDispatchDriver event_dispatch(event);

  CComVariant origin;
  HRESULT hr = event_dispatch.GetPropertyByName(L"origin", &origin);
  DCHECK(SUCCEEDED(hr) && origin.vt == VT_BSTR);
  if (FAILED(hr) || origin.vt != VT_BSTR) {
    NOTREACHED() << "No origin on event";
    return;
  }

  CComVariant data;
  hr = event_dispatch.GetPropertyByName(L"data", &data);
  DCHECK(SUCCEEDED(hr) && data.vt == VT_BSTR);
  if (FAILED(hr) || data.vt != VT_BSTR) {
    NOTREACHED() << "No data on event";
    return;
  }

  // Forward to the sink.
  event_sink_->OnCfPrivateMessage(V_BSTR(&data), V_BSTR(&origin), target);
}

STDMETHODIMP_(void) ChromeFrameHost::SetChromeProfileName(
    const wchar_t* chrome_profile_name) {
  chrome_profile_name_ = chrome_profile_name;
  DLOG(INFO) << "Assigned profile name " << chrome_profile_name_;
}
<commit_msg>Fixed return value of CFHost::getSession() BUG=none TEST=none<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ChromeFrameHost implementation.
#include "ceee/ie/common/chrome_frame_host.h"

#include <algorithm>
#include <vector>

#include "base/logging.h"
#include "ceee/common/com_utils.h"
#include "ceee/common/process_utils_win.h"
#include "ceee/ie/common/ceee_module_util.h"
#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/common/chrome_switches.h"

#include "toolband.h"  // NOLINT

namespace ext = extension_automation_constants;

_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_ =
    { CC_STDCALL, VT_EMPTY, 1, { VT_DISPATCH } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_long_ =
    { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_bstr_ =
    { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_BSTR } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_idispatch_variantptr_ =
    { CC_STDCALL, VT_EMPTY, 2, { VT_DISPATCH, VT_BYREF | VT_VARIANT } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_bstr_i4_=
    { CC_STDCALL, VT_EMPTY, 2, { VT_BSTR, VT_I4 } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_bstrarray_=
    { CC_STDCALL, VT_EMPTY, 1, { VT_ARRAY | VT_BSTR } };
_ATL_FUNC_INFO ChromeFrameHost::handler_type_void_=
    { CC_STDCALL, VT_EMPTY, 0, { } };

// {AFA3E2CF-2C8E-4546-8CD0-A2D93759A4DE}
extern const GUID IID_IChromeFrameHost =
  { 0xafa3e2cf, 0x2c8e, 0x4546,
      { 0x8c, 0xd0, 0xa2, 0xd9, 0x37, 0x59, 0xa4, 0xde } };

ChromeFrameHost::ChromeFrameHost()
    : document_loaded_(false), origin_(ext::kAutomationOrigin) {
  LOG(INFO) << "Create ChromeFrameHost(" << this << ")";
}

ChromeFrameHost::~ChromeFrameHost() {
  LOG(INFO) << "Destroy ChromeFrameHost(" << this << ")";
}

HRESULT ChromeFrameHost::FinalConstruct() {
  return S_OK;
}

void ChromeFrameHost::FinalRelease() {
}

STDMETHODIMP ChromeFrameHost::GetWantsPrivileged(boolean* wants_privileged) {
  *wants_privileged = true;
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::GetChromeExtraArguments(BSTR* args) {
  DCHECK(args);

  // Extra arguments are passed on verbatim, so we add the -- prefix.
  CComBSTR str = "--";
  str.Append(switches::kEnableExperimentalExtensionApis);

  *args = str.Detach();
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::GetChromeProfileName(BSTR* profile_name) {
  return chrome_profile_name_.CopyTo(profile_name);
}

STDMETHODIMP ChromeFrameHost::GetExtensionApisToAutomate(
    BSTR* functions_enabled) {
  DCHECK(functions_enabled != NULL);
  HRESULT hr = S_FALSE;
  if (event_sink_ != NULL) {
    hr = event_sink_->OnCfGetExtensionApisToAutomate(functions_enabled);
#ifndef NDEBUG
    if (*functions_enabled != NULL) {
      // Only one chrome frame host is allowed to return a list of functions
      // to enable automation on, so make sure we are the one and only.
      std::wstring event_name(L"google-ceee-apiautomation!");

      DCHECK(chrome_profile_name_ != NULL);
      if (chrome_profile_name_ != NULL)
        event_name += chrome_profile_name_;

      std::replace(event_name.begin(), event_name.end(), '\\', '!');
      std::transform(
          event_name.begin(), event_name.end(), event_name.begin(), tolower);
      automating_extension_api_.Set(
          ::CreateEvent(NULL, TRUE, TRUE, event_name.c_str()));
      DWORD we = ::GetLastError();
      DCHECK(automating_extension_api_ != NULL &&
             we != ERROR_ALREADY_EXISTS &&
             we != ERROR_ACCESS_DENIED);
    }
#endif  // NDEBUG
  }
  return hr;
}

HRESULT ChromeFrameHost::Initialize() {
  return S_OK;
}

STDMETHODIMP ChromeFrameHost::TearDown() {
  if (IsWindow()) {
    // TearDown the ActiveX host window.
    CAxWindow host(m_hWnd);
    CComPtr<IObjectWithSite> host_with_site;
    HRESULT hr = host.QueryHost(&host_with_site);
    if (SUCCEEDED(hr))
      host_with_site->SetSite(NULL);

    DestroyWindow();
  }

  if (chrome_frame_)
    ChromeFrameEvents::DispEventUnadvise(chrome_frame_);

  chrome_frame_.Release();
#ifndef NDEBUG
  automating_extension_api_.Close();
#endif
  return S_OK;
}

STDMETHODIMP_(void) ChromeFrameHost::SetEventSink(
    IChromeFrameHostEvents* event_sink) {
  event_sink_ = event_sink;
}

HRESULT ChromeFrameHost::InstallExtension(BSTR crx_path) {
  if (chrome_frame_) {
    return chrome_frame_->installExtension(crx_path);
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::LoadExtension(BSTR extension_dir) {
  if (chrome_frame_) {
    return chrome_frame_->installExtension(extension_dir);
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::GetEnabledExtensions() {
  if (chrome_frame_) {
    return chrome_frame_->getEnabledExtensions();
  } else {
    NOTREACHED();
    return E_UNEXPECTED;
  }
}

HRESULT ChromeFrameHost::GetSessionId(int* session_id) {
  if (chrome_frame_) {
    CComQIPtr<IChromeFrameInternal> chrome_frame_internal_(chrome_frame_);
    if (chrome_frame_internal_) {
      return chrome_frame_internal_->getSessionId(session_id);
    } else {
      *session_id = kInvalidChromeSessionId;
      return S_OK;
    }
  }
  NOTREACHED();
  return E_UNEXPECTED;
}

void ChromeFrameHost::OnFinalMessage(HWND window) {
  GetUnknown()->Release();
}

HRESULT ChromeFrameHost::SetChildSite(IUnknown* child) {
  if (child == NULL)
    return E_POINTER;

  HRESULT hr = S_OK;
  CComPtr<IObjectWithSite> child_site;
  hr = child->QueryInterface(&child_site);
  if (SUCCEEDED(hr))
    hr = child_site->SetSite(GetUnknown());

  return hr;
}

LRESULT ChromeFrameHost::OnCreate(LPCREATESTRUCT lpCreateStruct) {
  // Grab a self-reference.
  GetUnknown()->AddRef();

  return 0;
}

HRESULT ChromeFrameHost::SetUrl(BSTR url) {
  HRESULT hr = chrome_frame_->put_src(url);
  DCHECK(SUCCEEDED(hr)) << "Failed to navigate Chrome Frame: " <<
    com::LogHr(hr);
  return hr;
}

STDMETHODIMP ChromeFrameHost::StartChromeFrame() {
  DCHECK(!IsWindow());

  // Create a message window to host our control.
  if (NULL == Create(HWND_MESSAGE))
    return E_FAIL;

  // Create a host window instance.
  CComPtr<IAxWinHostWindow> host;
  HRESULT hr = CreateActiveXHost(&host);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to create ActiveX host window: " << com::LogHr(hr);
    return hr;
  }

  // We're the site for the host window, this needs to be in place
  // before we attach ChromeFrame to the ActiveX control window, so
  // as to allow it to probe our service provider.
  hr = SetChildSite(host);
  DCHECK(SUCCEEDED(hr));

  // Create the chrome frame instance.
  hr = CreateChromeFrame(&chrome_frame_);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed create Chrome Frame: " << com::LogHr(hr);
    return hr;
  }

  // And attach it to our window. This causes the host to subclass
  // our window and attach itself to it.
  hr = host->AttachControl(chrome_frame_, m_hWnd);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to attach Chrome Frame to the host" << com::LogHr(hr);
    return hr;
  }

  // Hook up the chrome frame event listener.
  hr = ChromeFrameEvents::DispEventAdvise(chrome_frame_);
  if (FAILED(hr)) {
    LOG(ERROR) << "Failed to hook up event sink: " << com::LogHr(hr);
    return hr;
  }

  return hr;
}

HRESULT ChromeFrameHost::CreateActiveXHost(IAxWinHostWindow** host) {
  return CAxHostWindow::CreateInstance(host);
}

HRESULT ChromeFrameHost::CreateChromeFrame(IChromeFrame** chrome_frame) {
  CComPtr<IChromeFrame> new_cf;
  HRESULT hr = new_cf.CoCreateInstance(L"ChromeTab.ChromeFrame");
  if (SUCCEEDED(hr))
    hr = new_cf.CopyTo(chrome_frame);

  return hr;
}

STDMETHODIMP ChromeFrameHost::PostMessage(BSTR message, BSTR target) {
  if (!document_loaded_) {
    PostedMessage posted_message = { message, target };
    posted_messages_.push_back(posted_message);
    return S_FALSE;
  }

  HRESULT hr = chrome_frame_->postPrivateMessage(message, origin_, target);

  return hr;
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfLoad(IDispatch* event) {
  DLOG(INFO) << "OnCfLoad";
  if (document_loaded_) {
    // If we were already loaded, our list should be empty.
    DCHECK(posted_messages_.empty());
    return;
  }
  document_loaded_ = true;

  // Flush all posted messages.
  PostedMessageList::iterator it(posted_messages_.begin());
  for (; it != posted_messages_.end(); ++it) {
    HRESULT hr = chrome_frame_->postPrivateMessage(it->message, origin_,
                                                   it->target);
    DCHECK(SUCCEEDED(hr)) << "postPrivateMessage failed with: " <<
        com::LogHr(hr);
  }
  posted_messages_.clear();
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfLoadError(IDispatch* event) {
  DLOG(ERROR) << "OnCfLoadError";
  DCHECK(false) << "OnCfLoadError";
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfExtensionReady(BSTR path,
                                                        int response) {
  DLOG(INFO) << "OnCfExtensionReady: " << path << ", " << response;
  // Early exit if there's no sink.
  if (event_sink_ == NULL)
    return;
  event_sink_->OnCfExtensionReady(path, response);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfGetEnabledExtensionsComplete(
    SAFEARRAY* extension_directories) {
  DLOG(INFO) << "OnCfGetEnabledExtensionsComplete";
  if (event_sink_)
    event_sink_->OnCfGetEnabledExtensionsComplete(extension_directories);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfChannelError() {
  DCHECK(false) << "OnCfChannelError means that Chrome has Crashed!";
  if (event_sink_)
    event_sink_->OnCfChannelError();
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfMessage(IDispatch* event) {
  DLOG(INFO) << "OnCfMessage";
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfReadyStateChanged(LONG state) {
  DLOG(INFO) << "OnCfReadyStateChanged(" << state << ")";
  if (event_sink_)
    event_sink_->OnCfReadyStateChanged(state);
}

STDMETHODIMP_(void) ChromeFrameHost::OnCfPrivateMessage(IDispatch* event,
                                                        BSTR target) {
  // Early exit if there's no sink.
  if (event_sink_ == NULL)
    return;

  // Make sure that the message has a "data" member and get it.  This should
  // be a JSON-encoded command to execute.
  CComDispatchDriver event_dispatch(event);

  CComVariant origin;
  HRESULT hr = event_dispatch.GetPropertyByName(L"origin", &origin);
  DCHECK(SUCCEEDED(hr) && origin.vt == VT_BSTR);
  if (FAILED(hr) || origin.vt != VT_BSTR) {
    NOTREACHED() << "No origin on event";
    return;
  }

  CComVariant data;
  hr = event_dispatch.GetPropertyByName(L"data", &data);
  DCHECK(SUCCEEDED(hr) && data.vt == VT_BSTR);
  if (FAILED(hr) || data.vt != VT_BSTR) {
    NOTREACHED() << "No data on event";
    return;
  }

  // Forward to the sink.
  event_sink_->OnCfPrivateMessage(V_BSTR(&data), V_BSTR(&origin), target);
}

STDMETHODIMP_(void) ChromeFrameHost::SetChromeProfileName(
    const wchar_t* chrome_profile_name) {
  chrome_profile_name_ = chrome_profile_name;
  DLOG(INFO) << "Assigned profile name " << chrome_profile_name_;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_CONTRIB_REP_ONE_MIN_MAX_HPP
#define TAOCPP_PEGTL_INCLUDE_CONTRIB_REP_ONE_MIN_MAX_HPP

#include <algorithm>

#include "../config.hpp"

#include "../analysis/counted.hpp"

#include "../internal/bump_help.hpp"
#include "../internal/skip_control.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         template< unsigned Min, unsigned Max, char C >
         struct rep_one_min_max
         {
            using analyze_t = analysis::counted< analysis::rule_type::ANY, Min >;

            static_assert( Min <= Max, "invalid rep_one_min_max rule (maximum number of repetitions smaller than minimum)" );

            template< typename Input >
            static bool match( Input& in )
            {
               const auto size = in.size( Max + 1 );
               if( size < Min ) {
                  return false;
               }
               std::size_t i = 0;
               for( ; i != Min; ++i ) {
                  if( in.peek_char( i ) != C ) {
                     return false;
                  }
               }
               const auto n = std::min( std::size_t( Max ), std::size_t( size ) );
               for( ; i != n; ++i ) {
                  if( in.peek_char( i ) != C ) {
                     bump_help< result_on_found::SUCCESS, Input, char, C >( in, i );
                     return true;
                  }
               }
               if( ( size <= Max ) || ( in.peek_char( Max ) != C ) ) {
                  bump_help< result_on_found::SUCCESS, Input, char, C >( in, i );
                  return true;
               }
               return false;
            }
         };

         template< unsigned Min, unsigned Max, char C >
         struct skip_control< rep_one_min_max< Min, Max, C > > : std::true_type
         {
         };

      } // namespace internal

      inline namespace ascii
      {
         template< unsigned Min, unsigned Max, char C > struct rep_one_min_max : internal::rep_one_min_max< Min, Max, C > {};
         struct ellipsis : internal::rep_one_min_max< 3, 3, '.' > {};

      } // namespace ascii

   } // namespace TAOCPP_PEGTL_NAMESPACE

} // namespace tao

#endif
<commit_msg>Simplify.<commit_after>// Copyright (c) 2017 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/

#ifndef TAOCPP_PEGTL_INCLUDE_CONTRIB_REP_ONE_MIN_MAX_HPP
#define TAOCPP_PEGTL_INCLUDE_CONTRIB_REP_ONE_MIN_MAX_HPP

#include <algorithm>

#include "../config.hpp"

#include "../analysis/counted.hpp"

#include "../internal/bump_help.hpp"
#include "../internal/skip_control.hpp"

namespace tao
{
   namespace TAOCPP_PEGTL_NAMESPACE
   {
      namespace internal
      {
         template< unsigned Min, unsigned Max, char C >
         struct rep_one_min_max
         {
            using analyze_t = analysis::counted< analysis::rule_type::ANY, Min >;

            static_assert( Min <= Max, "invalid rep_one_min_max rule (maximum number of repetitions smaller than minimum)" );

            template< typename Input >
            static bool match( Input& in )
            {
               const auto size = in.size( Max + 1 );
               std::size_t i = 0;
               while( ( i < size ) && ( in.peek_char( i ) == C ) ) {
                  ++i;
               }
               if( ( Min <= i ) && ( i <= Max ) ) {
                  bump_help< result_on_found::SUCCESS, Input, char, C >( in, i );
                  return true;
               }
               return false;
            }
         };

         template< unsigned Min, unsigned Max, char C >
         struct skip_control< rep_one_min_max< Min, Max, C > > : std::true_type
         {
         };

      } // namespace internal

      inline namespace ascii
      {
         template< unsigned Min, unsigned Max, char C > struct rep_one_min_max : internal::rep_one_min_max< Min, Max, C > {};
         struct ellipsis : internal::rep_one_min_max< 3, 3, '.' > {};

      } // namespace ascii

   } // namespace TAOCPP_PEGTL_NAMESPACE

} // namespace tao

#endif
<|endoftext|>


<commit_before>
// LuaChunkStay.cpp

// Implements the cLuaChunkStay class representing a cChunkStay binding for plugins, used by cWorld:ChunkStay() Lua API

#include "Globals.h"
#include "LuaChunkStay.h"
#include "PluginLua.h"

cLuaChunkStay::cLuaChunkStay(cPluginLua & a_Plugin) :
	m_Plugin(a_Plugin),
	m_LuaState(NULL)
{
}

bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos)
{
	// This function is expected to be called just once, with all the coords in a table
	ASSERT(m_Chunks.empty());

	cPluginLua::cOperation Op(m_Plugin);
	cLuaState & L = Op();

	// Check that we got a table:
	if (!lua_istable(L, a_ChunkCoordTableStackPos))
	{
		LOGWARNING("%s: The parameter is not a table of coords (got %s). Ignoring the call.",
			__FUNCTION__, lua_typename(L, lua_type(L, a_ChunkCoordTableStackPos))
		);
		L.LogStackTrace();
		return false;
	}

	// Add each set of coords:
	int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
	m_Chunks.reserve((size_t)NumChunks);
	for (int idx = 1; idx <= NumChunks; idx++)
	{
		// Push the idx-th element of the array onto stack top, check that it's a table:
		lua_rawgeti(L, a_ChunkCoordTableStackPos, idx);
		if (!lua_istable(L, -1))
		{
			LOGWARNING("%s: Element #%d is not a table (got %s). Ignoring the element.",
				__FUNCTION__, idx, lua_typename(L, -1)
			);
			L.LogStackTrace();
			lua_pop(L, 1);
			continue;
		}
		AddChunkCoord(L, idx);
		lua_pop(L, 1);
	}

	// If there are no chunks, log a warning and return failure:
	if (m_Chunks.empty())
	{
		LOGWARNING("%s: Zero chunks to stay.", __FUNCTION__);
		L.LogStackTrace();
		return false;
	}

	// All ok
	return true;
}

void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
{
	// Check that the element has 2 coords:
	int NumCoords = luaL_getn(L, -1);
	if (NumCoords != 2)
	{
		LOGWARNING("%s: Element #%d doesn't contain 2 coords (got %d). Ignoring the element.",
			__FUNCTION__, a_Index, NumCoords
		);
		return;
	}

	// Read the two coords from the element:
	lua_rawgeti(L, -1, 1);
	lua_rawgeti(L, -2, 2);
	int ChunkX = luaL_checkint(L, -2);
	int ChunkZ = luaL_checkint(L, -1);
	lua_pop(L, 2);

	// Check that a coord is not yet present:
	for (cChunkCoordsVector::iterator itr = m_Chunks.begin(), end = m_Chunks.end(); itr != end; ++itr)
	{
		if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
		{
			LOGWARNING("%s: Element #%d is a duplicate, ignoring it.",
				__FUNCTION__, a_Index
			);
			return;
		}
	}  // for itr - m_Chunks[]

	m_Chunks.push_back(cChunkCoords(ChunkX, ChunkZ));
}

void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos)
{
	// Get the references to the callback functions:
	m_LuaState = &m_Plugin.GetLuaState();
	m_OnChunkAvailable.RefStack(*m_LuaState, a_OnChunkAvailableStackPos);
	m_OnAllChunksAvailable.RefStack(*m_LuaState, a_OnAllChunksAvailableStackPos);

	// Enable the ChunkStay:
	super::Enable(a_ChunkMap);
}

void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
	cPluginLua::cOperation Op(m_Plugin);
	Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ);
}

bool cLuaChunkStay::OnAllChunksAvailable(void)
{
	{
		// Call the callback:
		cPluginLua::cOperation Op(m_Plugin);
		Op().Call((int)m_OnAllChunksAvailable);

		// Remove the callback references - they won't be needed anymore
		m_OnChunkAvailable.UnRef();
		m_OnAllChunksAvailable.UnRef();
	}

	// Disable the ChunkStay by returning true
	return true;
}

void cLuaChunkStay::OnDisabled(void)
{
	// This object is no longer needed, delete it
	delete this;
}

<commit_msg>LuaChunkStay: Fixed a crash on unused callback.<commit_after>
// LuaChunkStay.cpp

// Implements the cLuaChunkStay class representing a cChunkStay binding for plugins, used by cWorld:ChunkStay() Lua API

#include "Globals.h"
#include "LuaChunkStay.h"
#include "PluginLua.h"

cLuaChunkStay::cLuaChunkStay(cPluginLua & a_Plugin) :
	m_Plugin(a_Plugin),
	m_LuaState(NULL)
{
}

bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos)
{
	// This function is expected to be called just once, with all the coords in a table
	ASSERT(m_Chunks.empty());

	cPluginLua::cOperation Op(m_Plugin);
	cLuaState & L = Op();

	// Check that we got a table:
	if (!lua_istable(L, a_ChunkCoordTableStackPos))
	{
		LOGWARNING("%s: The parameter is not a table of coords (got %s). Ignoring the call.",
			__FUNCTION__, lua_typename(L, lua_type(L, a_ChunkCoordTableStackPos))
		);
		L.LogStackTrace();
		return false;
	}

	// Add each set of coords:
	int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
	m_Chunks.reserve((size_t)NumChunks);
	for (int idx = 1; idx <= NumChunks; idx++)
	{
		// Push the idx-th element of the array onto stack top, check that it's a table:
		lua_rawgeti(L, a_ChunkCoordTableStackPos, idx);
		if (!lua_istable(L, -1))
		{
			LOGWARNING("%s: Element #%d is not a table (got %s). Ignoring the element.",
				__FUNCTION__, idx, lua_typename(L, -1)
			);
			L.LogStackTrace();
			lua_pop(L, 1);
			continue;
		}
		AddChunkCoord(L, idx);
		lua_pop(L, 1);
	}

	// If there are no chunks, log a warning and return failure:
	if (m_Chunks.empty())
	{
		LOGWARNING("%s: Zero chunks to stay.", __FUNCTION__);
		L.LogStackTrace();
		return false;
	}

	// All ok
	return true;
}

void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index)
{
	// Check that the element has 2 coords:
	int NumCoords = luaL_getn(L, -1);
	if (NumCoords != 2)
	{
		LOGWARNING("%s: Element #%d doesn't contain 2 coords (got %d). Ignoring the element.",
			__FUNCTION__, a_Index, NumCoords
		);
		return;
	}

	// Read the two coords from the element:
	lua_rawgeti(L, -1, 1);
	lua_rawgeti(L, -2, 2);
	int ChunkX = luaL_checkint(L, -2);
	int ChunkZ = luaL_checkint(L, -1);
	lua_pop(L, 2);

	// Check that a coord is not yet present:
	for (cChunkCoordsVector::iterator itr = m_Chunks.begin(), end = m_Chunks.end(); itr != end; ++itr)
	{
		if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
		{
			LOGWARNING("%s: Element #%d is a duplicate, ignoring it.",
				__FUNCTION__, a_Index
			);
			return;
		}
	}  // for itr - m_Chunks[]

	m_Chunks.push_back(cChunkCoords(ChunkX, ChunkZ));
}

void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos)
{
	// Get the references to the callback functions:
	m_LuaState = &m_Plugin.GetLuaState();
	m_OnChunkAvailable.RefStack(*m_LuaState, a_OnChunkAvailableStackPos);
	m_OnAllChunksAvailable.RefStack(*m_LuaState, a_OnAllChunksAvailableStackPos);

	// Enable the ChunkStay:
	super::Enable(a_ChunkMap);
}

void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
	if (m_OnChunkAvailable.IsValid())
	{
		cPluginLua::cOperation Op(m_Plugin);
		Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ);
	}
}

bool cLuaChunkStay::OnAllChunksAvailable(void)
{
	if (m_OnAllChunksAvailable.IsValid())
	{
		// Call the callback:
		cPluginLua::cOperation Op(m_Plugin);
		Op().Call((int)m_OnAllChunksAvailable);

		// Remove the callback references - they won't be needed anymore
		m_OnChunkAvailable.UnRef();
		m_OnAllChunksAvailable.UnRef();
	}

	// Disable the ChunkStay by returning true
	return true;
}

void cLuaChunkStay::OnDisabled(void)
{
	// This object is no longer needed, delete it
	delete this;
}

<|endoftext|>