<commit_before>//  (C) Copyright Gennadiy Rozental 2011-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//!@file
//!@brief Random generator
// ***************************************************************************

#ifndef BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER
#define BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER

// Boost.Test
#include <boost/test/data/config.hpp>

#ifndef BOOST_TEST_NO_RANDOM_DATASET_AVAILABLE

#include <boost/test/data/monomorphic/generate.hpp>
#include <boost/test/data/monomorphic/generators/keywords.hpp>

// STL
#include <random>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace unit_test {
namespace data {

namespace {
nfp::keyword<struct seed_t>         seed;
nfp::keyword<struct distrbution_t>  distribution;
nfp::keyword<struct engine_t>       engine;
} // local namespace

namespace monomorphic {

namespace ds_detail {
template<typename SampleType>
struct default_distribution {
    typedef typename mpl::if_<std::is_integral<SampleType>,
                              std::uniform_int_distribution<SampleType>,
                              std::uniform_real_distribution<SampleType> >::type type;
};

} // namespace ds_detail

// ************************************************************************** //
// **************                   random_t                   ************** //
// ************************************************************************** //

template<typename SampleType        = double,
         typename DistributionType  = typename ds_detail::default_distribution<SampleType>::type,
         typename EngineType        = std::default_random_engine>
class random_t {
public:
    typedef SampleType          data_type;
    typedef DistributionType    distr_type;
    typedef EngineType          engine_type;

    random_t()
    : m_distribution()
    , m_engine( std::random_device()() )
    {}
    explicit random_t( distr_type&& d )
    : m_distribution( std::forward<distr_type>(d) )
    , m_engine( std::random_device()() ){}
    random_t( engine_type&& e, distr_type&& d )
    : m_distribution( std::forward<distr_type>(d) )
    , m_engine( std::forward<engine_type>(e) ){}

    // Generator interface
    data::size_t        capacity() const    { return BOOST_TEST_DS_INFINITE_SIZE; }
    SampleType          next()
    {
        return m_distribution( m_engine );
    }
    void                reset()             {}
    template<typename SeedType>
    void seed( SeedType&& seed )            { m_engine.seed( std::forward<SeedType>( seed ) ); }

private:
    // Data members
    DistributionType    m_distribution;
    EngineType          m_engine;
};

//____________________________________________________________________________//

} // namespace monomorphic

//! @brief Returns an infinite sequence of random numbers.
//!
//! The following overloads are available:
//! @code
//! auto d = random();
//! auto d = random(begin, end);
//! auto d = random(params);
//! @endcode
//!
//!
//! - The first overload uses the default distribution, which is uniform and which elements
//!   are @c double type (the values are in [0, 1) ).
//! - The second overload generates numbers in the given interval. The distribution is uniform (in [begin, end)
//!   for real numbers, and in [begin, end] for integers). The type of the distribution is deduced from the type
//!   of the @c begin and @c end parameters.
//! - The third overload generates numbers using the named parameter inside @c params , which are:
//!   - @c distribution: the distribution used. In this overload, since the type of the samples cannot be deduced,
//!     the samples are of type @c double and the distribution is uniform real in [0, 1).
//!   - @c seed: the seed for generating the values
//!   - @c engine: the random number generator engine
//!
//! The function returns an object that implements the dataset API.
//! @note This function is available only on C++11 capable compilers.
template <typename T>
inline monomorphic::generated_by< monomorphic::random_t<> > random()
{
    return monomorphic::generated_by<monomorphic::random_t<>>( monomorphic::random_t<>() );
}

//____________________________________________________________________________//

/// @overload boost::unit_test::data::random()
template<typename SampleType>
inline monomorphic::generated_by< monomorphic::random_t<SampleType> >
random( SampleType begin, SampleType end )
{
    typedef monomorphic::random_t<SampleType> Gen;
    typedef typename Gen::distr_type distr_type;
    return monomorphic::generated_by<Gen>( Gen( distr_type(begin,end) ) );
}

//____________________________________________________________________________//

namespace ds_detail {
template<typename Params>
struct random_gen_type {
    typedef typename nfp::param_type<Params,decltype(distribution),std::uniform_real_distribution<>>::type distr_type;
    typedef typename nfp::param_type<Params,decltype(engine),std::default_random_engine>::type engine_type;
    typedef typename distr_type::result_type sample_type;

    typedef monomorphic::random_t<sample_type,distr_type,engine_type> type;
};

}

/// @overload boost::unit_test::data::random()
template<typename Params>
inline monomorphic::generated_by<typename ds_detail::random_gen_type<Params>::type>
random( Params const& params )
{
    typedef typename ds_detail::random_gen_type<Params>::type Gen;
    typedef typename Gen::distr_type distr_type;
    typedef typename Gen::engine_type engine_type;

    std::random_device rd;
    engine_type E;
//    engine_type E( rd );
    if( params.has(engine) )
        E = params[engine];

    distr_type D;
    if( params.has(distribution) )
        D = params[distribution];

    Gen G( std::move(E), std::move(D) );

    if( params.has(seed) )
        G.seed( params[seed] );

    return monomorphic::generated_by<Gen>( std::move(G) );
}

} // namespace data
} // namespace unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_NO_RANDOM_DATASET_AVAILABLE

#endif // BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER
<commit_msg>Allowing documentation for random<commit_after>//  (C) Copyright Gennadiy Rozental 2011-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//!@file
//!@brief Random generator
// ***************************************************************************

#ifndef BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER
#define BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER

// Boost.Test
#include <boost/test/data/config.hpp>

#if !defined(BOOST_TEST_NO_RANDOM_DATASET_AVAILABLE) || defined(BOOST_TEST_DOXYGEN_DOC__)

#include <boost/test/data/monomorphic/generate.hpp>
#include <boost/test/data/monomorphic/generators/keywords.hpp>

// STL
#include <random>

#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace unit_test {
namespace data {

namespace {
nfp::keyword<struct seed_t>         seed;
nfp::keyword<struct distrbution_t>  distribution;
nfp::keyword<struct engine_t>       engine;
} // local namespace

namespace monomorphic {

namespace ds_detail {
template<typename SampleType>
struct default_distribution {
    typedef typename mpl::if_<std::is_integral<SampleType>,
                              std::uniform_int_distribution<SampleType>,
                              std::uniform_real_distribution<SampleType> >::type type;
};

} // namespace ds_detail

// ************************************************************************** //
// **************                   random_t                   ************** //
// ************************************************************************** //

template<typename SampleType        = double,
         typename DistributionType  = typename ds_detail::default_distribution<SampleType>::type,
         typename EngineType        = std::default_random_engine>
class random_t {
public:
    typedef SampleType          data_type;
    typedef DistributionType    distr_type;
    typedef EngineType          engine_type;

    random_t()
    : m_distribution()
    , m_engine( std::random_device()() )
    {}
    explicit random_t( distr_type&& d )
    : m_distribution( std::forward<distr_type>(d) )
    , m_engine( std::random_device()() ){}
    random_t( engine_type&& e, distr_type&& d )
    : m_distribution( std::forward<distr_type>(d) )
    , m_engine( std::forward<engine_type>(e) ){}

    // Generator interface
    data::size_t        capacity() const    { return BOOST_TEST_DS_INFINITE_SIZE; }
    SampleType          next()
    {
        return m_distribution( m_engine );
    }
    void                reset()             {}
    template<typename SeedType>
    void seed( SeedType&& seed )            { m_engine.seed( std::forward<SeedType>( seed ) ); }

private:
    // Data members
    DistributionType    m_distribution;
    EngineType          m_engine;
};

//____________________________________________________________________________//

} // namespace monomorphic

//! @brief Returns an infinite sequence of random numbers.
//!
//! The following overloads are available:
//! @code
//! auto d = random();
//! auto d = random(begin, end);
//! auto d = random(params);
//! @endcode
//!
//!
//! - The first overload uses the default distribution, which is uniform and which elements
//!   are @c double type (the values are in [0, 1) ).
//! - The second overload generates numbers in the given interval. The distribution is uniform (in [begin, end)
//!   for real numbers, and in [begin, end] for integers). The type of the distribution is deduced from the type
//!   of the @c begin and @c end parameters.
//! - The third overload generates numbers using the named parameter inside @c params , which are:
//!   - @c distribution: the distribution used. In this overload, since the type of the samples cannot be deduced,
//!     the samples are of type @c double and the distribution is uniform real in [0, 1).
//!   - @c seed: the seed for generating the values
//!   - @c engine: the random number generator engine
//!
//! The function returns an object that implements the dataset API.
//! @note This function is available only on C++11 capable compilers.
template <typename T>
inline monomorphic::generated_by< monomorphic::random_t<> > random()
{
    return monomorphic::generated_by<monomorphic::random_t<>>( monomorphic::random_t<>() );
}

//____________________________________________________________________________//

/// @overload boost::unit_test::data::random()
template<typename SampleType>
inline monomorphic::generated_by< monomorphic::random_t<SampleType> >
random( SampleType begin, SampleType end )
{
    typedef monomorphic::random_t<SampleType> Gen;
    typedef typename Gen::distr_type distr_type;
    return monomorphic::generated_by<Gen>( Gen( distr_type(begin,end) ) );
}

//____________________________________________________________________________//

namespace ds_detail {
template<typename Params>
struct random_gen_type {
    typedef typename nfp::param_type<Params,decltype(distribution),std::uniform_real_distribution<>>::type distr_type;
    typedef typename nfp::param_type<Params,decltype(engine),std::default_random_engine>::type engine_type;
    typedef typename distr_type::result_type sample_type;

    typedef monomorphic::random_t<sample_type,distr_type,engine_type> type;
};

}

/// @overload boost::unit_test::data::random()
template<typename Params>
inline monomorphic::generated_by<typename ds_detail::random_gen_type<Params>::type>
random( Params const& params )
{
    typedef typename ds_detail::random_gen_type<Params>::type Gen;
    typedef typename Gen::distr_type distr_type;
    typedef typename Gen::engine_type engine_type;

    std::random_device rd;
    engine_type E;
//    engine_type E( rd );
    if( params.has(engine) )
        E = params[engine];

    distr_type D;
    if( params.has(distribution) )
        D = params[distribution];

    Gen G( std::move(E), std::move(D) );

    if( params.has(seed) )
        G.seed( params[seed] );

    return monomorphic::generated_by<Gen>( std::move(G) );
}

} // namespace data
} // namespace unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_NO_RANDOM_DATASET_AVAILABLE

#endif // BOOST_TEST_DATA_MONOMORPHIC_GENERATORS_RANDOM_HPP_101512GER
<|endoftext|>


<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 linear_observation_model.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP
#define FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP

#include <fl/util/traits.hpp>
#include <fl/util/descriptor.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/distribution/decorrelated_gaussian.hpp>
#include <fl/model/adaptive_model.hpp>
#include <fl/model/observation/interface/observation_density.hpp>
#include <fl/model/observation/interface/observation_model_interface.hpp>
#include <fl/model/observation/interface/additive_observation_function.hpp>
#include <fl/model/observation/interface/additive_uncorrelated_observation_function.hpp>

namespace fl
{

/**
 * \internal
 * Forward declaration
 */
template <typename ...> class LinearObservationModel;

/**
 * \ingroup observation_models
 * \internal
 */
template <typename Obsrv_, typename State_, typename Density>
class LinearObservationModel<Obsrv_, State_, Density>
    : public ObservationDensity<Obsrv_, State_>,                  // p(y|x)
      public AdditiveObservationFunction<Obsrv_, State_, Obsrv_>, // H*x + N*v
      public Descriptor
{
public:
    typedef Obsrv_ Obsrv;
    typedef State_ State;

    typedef ObservationDensity<Obsrv, State> DensityInterface;
    typedef AdditiveObservationFunction<Obsrv, State, Obsrv> AdditiveInterface;
    typedef typename AdditiveInterface::FunctionInterface FunctionInterface;

    /**
     * Linear model density. The density for linear model is the Gaussian over
     * observation space.
     */
    //typedef Gaussian<Obsrv> Density;

    /**
     * Observation model sensor matrix \f$H_t\f$ use in
     *
     * \f$ y_t  = H_t x_t + N_t v_t \f$
     */
    typedef Eigen::Matrix<
                typename State::Scalar,
                SizeOf<Obsrv>::Value,
                SizeOf<State>::Value
            > SensorMatrix;

    /**
     * Observation model noise matrix \f$N_t\f$ use in
     *
     * \f$ y_t  = H_t x_t + N_t v_t\f$
     *
     * In this linear model, the noise model matrix is equivalent to the
     * square root of the covariance of the model density. Hence, the
     * NoiseMatrix type is the same type as the second moment of the density.
     *
     * This is equivalent to
     *  > typedef typename Gaussian<Obsrv>::SecondMoment NoiseMatrix;
     */
    typedef typename AdditiveInterface::NoiseMatrix NoiseMatrix;

public:
    /**
     * Constructs a linear gaussian observation model
     * \param obsrv_dim     observation dimension if dynamic size
     * \param state_dim     state dimension if dynamic size
     */
    explicit
    LinearObservationModel(int obsrv_dim = DimensionOf<Obsrv>(),
                               int state_dim = DimensionOf<State>())
        : sensor_matrix_(SensorMatrix::Identity(obsrv_dim, state_dim)),
          density_(obsrv_dim)
    {
        assert(obsrv_dim > 0);
        assert(state_dim > 0);
    }

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

    /**
     * \brief expected_observation
     * \param state
     * \return
     */
    virtual Obsrv expected_observation(const State& state) const
    {
        return sensor_matrix_ * state;
    }

    virtual Real log_probability(const Obsrv& obsrv,
                                          const State& state) const
    {
        density_.mean(expected_observation(state));

        return density_.log_probability(obsrv);
    }

    virtual const SensorMatrix& sensor_matrix() const
    {
        return sensor_matrix_;
    }

    virtual const NoiseMatrix& noise_matrix() const
    {
        return density_.square_root();
    }

    virtual const NoiseMatrix& noise_covariance() const
    {
        return density_.covariance();
    }

    virtual int obsrv_dimension() const
    {
        return sensor_matrix_.rows();
    }

    virtual int noise_dimension() const
    {
        return density_.square_root().cols();
    }

    virtual int state_dimension() const
    {
        return sensor_matrix_.cols();
    }

    virtual void sensor_matrix(const SensorMatrix& sensor_mat)
    {
        sensor_matrix_ = sensor_mat;
    }

    virtual void noise_matrix(const NoiseMatrix& noise_mat)
    {
        density_.square_root(noise_mat);
    }

    virtual void noise_covariance(const NoiseMatrix& noise_mat_squared)
    {
        density_.covariance(noise_mat_squared);
    }

    virtual SensorMatrix create_sensor_matrix() const
    {
        auto H = sensor_matrix();
        H.setIdentity();
        return H;
    }

    virtual NoiseMatrix create_noise_matrix() const
    {
        auto N = noise_matrix();
        N.setIdentity();
        return N;
    }

    virtual std::string name() const
    {
        return "LinearObservationModel";
    }

    virtual std::string description() const
    {
        return "Linear observation model";
    }

protected:
    SensorMatrix sensor_matrix_;
    mutable Density density_;
};

/**
 * \ingroup observation_models
 *
 * This represents the linear gaussian observation model \f$p(y_t \mid x_t)\f$
 * governed by the linear equation
 *
 * \f$ y_t  = H_t x_t + N_t v_t \f$
 *
 * where \f$ y_t\f$ is the observation, \f$ x_t\f$ is the state. The matrix
 * \f$H_t\f$ is the sensor model mapping the state into the observation space.
 * The vector \f$ v_t \sim {\cal N}(v_t; 0, I)\f$ is a standard normal variate
 * which is mapped into the the observation space via the noise model matrix
 * \f$N_t\f$. Any Gaussian noise \f$\tilde{v}_t \sim {\cal N}(\tilde{v}_t ; 0,
 * R_t) \f$ can be represented via \f$\tilde{v}_t = N_t v_t\f$ with\f$N_t
 * = \sqrt{R_t}\f$. Hence, the linear equation may be restated as the more
 * familiar but equivalent form
 *
 * \f$ y_t  = H_t x_t + \tilde{v}_t \f$.
 */
template <typename Obsrv, typename State>
class LinearObservationModel<Obsrv, State>
#ifdef GENERATING_DOCUMENTATION
    : public LinearObservationModel<Obsrv_, State_, Density>
#else
    : public LinearObservationModel<Obsrv, State, Gaussian<Obsrv>>
#endif
{
public:
    /**
     * Constructs a linear gaussian observation model
     * \param obsrv_dim     observation dimension if dynamic size
     * \param state_dim     state dimension if dynamic size
     */
    explicit
    LinearObservationModel(int obsrv_dim = DimensionOf<Obsrv>(),
                           int state_dim = DimensionOf<State>())
        : LinearObservationModel<Obsrv, State, Gaussian<Obsrv>>(
              obsrv_dim, state_dim)
    { }
};

/**
 * \internal
 */
template <typename...> class LinearUncorrelatedObservationModel;

/**
 * \ingroup observation_models
 */
template <typename Obsrv, typename State>
class LinearUncorrelatedObservationModel<Obsrv, State>
#ifdef GENERATING_DOCUMENTATION
    : public LinearObservationModel<Obsrv_, State_, Density>
#else
    : public LinearObservationModel<Obsrv, State, DecorrelatedGaussian<Obsrv>>,
#endif
      public AdditiveUncorrelatedObservationFunction<Obsrv, State, Obsrv>
{
public:

    typedef AdditiveUncorrelatedObservationFunction<
                Obsrv, State, Obsrv
            > AdditiveUncorrelatedInterface;

    typedef typename AdditiveUncorrelatedInterface::NoiseDiagonal NoiseDiagonal;

    using AdditiveUncorrelatedInterface::covariance;
    using AdditiveUncorrelatedInterface::square_root;

    /**
     * Constructs a linear gaussian observation model
     *
     * \param obsrv_dim     observation dimension if dynamic size
     * \param state_dim     state dimension if dynamic size
     */
    explicit
    LinearUncorrelatedObservationModel(int obsrv_dim = DimensionOf<Obsrv>(),
                                       int state_dim = DimensionOf<State>())
        : LinearObservationModel<Obsrv, State, DecorrelatedGaussian<Obsrv>>(
              obsrv_dim, state_dim)
    { }

    virtual const NoiseDiagonal& noise_matrix_diagonal() const
    {
        return AdditiveUncorrelatedInterface::square_root();
    }

    virtual const NoiseDiagonal& noise_covariance_diagonal() const
    {
        return AdditiveUncorrelatedInterface::covariance();
    }
};

}

#endif
<commit_msg>Contains now only the general linear model<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 linear_observation_model.hpp
 * \date October 2014
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP
#define FL__MODEL__OBSERVATION__LINEAR_OBSERVATION_MODEL_HPP

#include <fl/util/traits.hpp>
#include <fl/util/descriptor.hpp>
#include <fl/distribution/gaussian.hpp>
#include <fl/distribution/decorrelated_gaussian.hpp>
#include <fl/model/adaptive_model.hpp>
#include <fl/model/observation/interface/observation_density.hpp>
#include <fl/model/observation/interface/observation_model_interface.hpp>
#include <fl/model/observation/interface/additive_observation_function.hpp>
#include <fl/model/observation/interface/additive_uncorrelated_observation_function.hpp>

namespace fl
{

/**
 * \internal
 * Forward declaration
 */
template <typename ...> class LinearObservationModel;

/**
 * \ingroup observation_models
 */
template <typename Obsrv_, typename State_, typename Density>
class LinearObservationModel<Obsrv_, State_, Density>
    : public ObservationDensity<Obsrv_, State_>,                  // p(y|x)
      public AdditiveObservationFunction<Obsrv_, State_, Obsrv_> // H*x + N*v

{
public:
    typedef Obsrv_ Obsrv;
    typedef State_ State;

    typedef ObservationDensity<Obsrv, State> DensityInterface;
    typedef AdditiveObservationFunction<Obsrv, State, Obsrv> AdditiveInterface;
    typedef typename AdditiveInterface::FunctionInterface FunctionInterface;

    /**
     * Linear model density. The density for linear model is the Gaussian over
     * observation space.
     */
    //typedef Gaussian<Obsrv> Density;

    /**
     * Observation model sensor matrix \f$H_t\f$ use in
     *
     * \f$ y_t  = H_t x_t + N_t v_t \f$
     */
    typedef Eigen::Matrix<
                typename State::Scalar,
                SizeOf<Obsrv>::Value,
                SizeOf<State>::Value
            > SensorMatrix;

    /**
     * Observation model noise matrix \f$N_t\f$ use in
     *
     * \f$ y_t  = H_t x_t + N_t v_t\f$
     *
     * In this linear model, the noise model matrix is equivalent to the
     * square root of the covariance of the model density. Hence, the
     * NoiseMatrix type is the same type as the second moment of the density.
     *
     * This is equivalent to
     *  > typedef typename Gaussian<Obsrv>::SecondMoment NoiseMatrix;
     */
    typedef typename AdditiveInterface::NoiseMatrix NoiseMatrix;

public:
    /**
     * Constructs a linear gaussian observation model
     * \param obsrv_dim     observation dimension if dynamic size
     * \param state_dim     state dimension if dynamic size
     */
    explicit
    LinearObservationModel(int obsrv_dim = DimensionOf<Obsrv>(),
                               int state_dim = DimensionOf<State>())
        : sensor_matrix_(SensorMatrix::Identity(obsrv_dim, state_dim)),
          density_(obsrv_dim)
    {
        assert(obsrv_dim > 0);
        assert(state_dim > 0);
    }

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

    /**
     * \brief expected_observation
     * \param state
     * \return
     */
    virtual Obsrv expected_observation(const State& state) const
    {
        return sensor_matrix_ * state;
    }

    virtual Real log_probability(const Obsrv& obsrv,
                                          const State& state) const
    {
        density_.mean(expected_observation(state));

        return density_.log_probability(obsrv);
    }

    virtual const SensorMatrix& sensor_matrix() const
    {
        return sensor_matrix_;
    }

    virtual const NoiseMatrix& noise_matrix() const
    {
        return density_.square_root();
    }

    virtual const NoiseMatrix& noise_covariance() const
    {
        return density_.covariance();
    }

    virtual int obsrv_dimension() const
    {
        return sensor_matrix_.rows();
    }

    virtual int noise_dimension() const
    {
        return density_.square_root().cols();
    }

    virtual int state_dimension() const
    {
        return sensor_matrix_.cols();
    }

    virtual void sensor_matrix(const SensorMatrix& sensor_mat)
    {
        sensor_matrix_ = sensor_mat;
    }

    virtual void noise_matrix(const NoiseMatrix& noise_mat)
    {
        density_.square_root(noise_mat);
    }

    virtual void noise_covariance(const NoiseMatrix& noise_mat_squared)
    {
        density_.covariance(noise_mat_squared);
    }

    virtual SensorMatrix create_sensor_matrix() const
    {
        auto H = sensor_matrix();
        H.setIdentity();
        return H;
    }

    virtual NoiseMatrix create_noise_matrix() const
    {
        auto N = noise_matrix();
        N.setIdentity();
        return N;
    }

protected:
    SensorMatrix sensor_matrix_;
    mutable Density density_;
};

}

#endif
<|endoftext|>


<commit_before>
#pragma once

#include <vector>

#include "base/not_null.hpp"
#include "integrators/symplectic_integrator.hpp"

namespace principia {

using base::not_null;

namespace integrators {

// The integrator defined in this class integrates Hamilton's equations for
// Hamiltonians of the form
//   H(q, p, t) = T(q, p) + V(q, t),
// with T quadratic in p, i.e.,
//  T(q, p) = ½ M(q)⁻¹(p, p)
// where M(q)⁻¹ is bilinear.  The flows of T and V must be known.
// A special treatment is provided for hamiltonians where M⁻¹ is independent of
// q and ∂V/∂qᵢ(q, t) is known.  In those cases the differential equation can be
// reformulated as q" = M⁻¹ F(q, t), where Fᵢ = ∂V/∂qᵢ.

// NOTE(egg): only the latter is implemented at this time.

// TODO(egg): a blurb on non-autonomy, it's slightly trickier than in the SPRK
// case.

// We follow the convention of McLachlan & Atela, calling the position nodes
// aᵢ and the momentum nodes bᵢ.  The following notations appear in the
// litterature:
//   (a, b) in McLachlan & Atela, as well as Candy & Rozmus;
//   (d, c) in Ruth, Yoshida, as well as Forest & Ruth;
//   (B, b) in Sofroniou & Spaletta.
// Moreover, we follow the convention of Sofroniou & Spaletta in calling the
// weights used for the time argument of the force computation cᵢ, with
// c₁ = 0, cᵢ = cᵢ₋₁ + aᵢ₋₁ for i > 1.

enum VanishingCoefficients {
  kNone,
  kFirstBVanishes,
  kLastAVanishes,
};

class SRKNIntegrator : public SymplecticIntegrator {
 protected:
  enum VanishingCoefficients {
   kNone,
   kFirstBVanishes,
   kLastAVanishes,
 };

 public:

  // The functors |evolve_kinetic| and |evolve_potential| respectively compute
  // exp(h{·, T})(q, p) given (q, p), and exp(h{·, V})(q, p) given (q, p, t).
  template<typename Position, typename Momentum,
           typename KineticFlow
           typename PotentialFlow>
  void SolveQuadraticKineticEnergy(
      KineticFlow evolve_kinetic,
      PotentialFlow evolve_potential,
      Parameters<Position, Momentum> const& parameters,
      not_null<Solution<Position, Momentum>*> const solution) const;

  // The functor |compute_acceleration| computes M⁻¹ F(q, t).
  template<typename Position, typename Velocity,
           typename RightHandSideComputation>
  void SolveTrivialKineticEnergyIncrement(
      RightHandSideComputation compute_acceleration,
      Parameters<Position, Velocity> const& parameters,
      not_null<Solution<Position, Velocity>*> const solution) const;

 protected:
  struct FirstSameAsLast {
    double first;
    double last;
  };

  VanishingCoefficients vanishing_coefficients_;
  // Null if, and only if, |vanishing_coefficients_ == kNone|.
  // If |vanishing_coefficients_ == kFirstBVanishes|, this contains the first
  // and last a coefficients.
  // If |vanishing_coefficients_ == FirstAVanishes|, this contains the first
  // and last b coefficients.
  // These are used to desynchronize and synchronize first-same-as-last
  // integrators.
  std::unique_ptr<FirstSameAsLast> first_same_as_last_

  int const stages_;

  // The position and momentum nodes.
  // If |vanishing_coefficients_ == kFirstBVanishes|, we do not store the first
  // b coefficient, and the last entry of |a_| is the sum of the first and last
  // a coefficients.
  std::vector<double> a_;
  std::vector<double> b_;

  // The weights.  Note that the first c coefficient is not stored if
  // |vanishing_coefficients_ == kFirstBVanishes|.
  std::vector<double> c_;
 private:
};

}  // namespace integrators
}  // namespace principia

#include "integrators/symplectic_partitioned_runge_kutta_integrator_body.hpp"
<commit_msg>a transpose of sorts<commit_after>
#pragma once

#include <vector>

#include "base/not_null.hpp"
#include "integrators/symplectic_integrator.hpp"

namespace principia {

using base::not_null;

namespace integrators {

// The integrator defined in this class integrates Hamilton's equations for
// Hamiltonians of the form
//   H(q, p, t) = T(q, p) + V(q, t),
// with T quadratic in p, i.e.,
//  T(q, p) = ½ pᵀM(q)⁻¹p
// where M(q)⁻¹ is a nonsingular matrix.  The flows of T and V must be known.
// A special treatment is provided for hamiltonians where M⁻¹ is independent of
// q and ∂V/∂qᵢ(q, t) is known.  In those cases the differential equation can be
// reformulated as q" = M⁻¹ F(q, t), where Fᵢ = ∂V/∂qᵢ.

// NOTE(egg): only the latter is implemented at this time.

// TODO(egg): a blurb on non-autonomy, it's slightly trickier than in the SPRK
// case.

// We follow the convention of McLachlan & Atela, calling the position nodes
// aᵢ and the momentum nodes bᵢ.  The following notations appear in the
// litterature:
//   (a, b) in McLachlan & Atela, as well as Candy & Rozmus;
//   (d, c) in Ruth, Yoshida, as well as Forest & Ruth;
//   (B, b) in Sofroniou & Spaletta.
// Moreover, we follow the convention of Sofroniou & Spaletta in calling the
// weights used for the time argument of the force computation cᵢ, with
// c₁ = 0, cᵢ = cᵢ₋₁ + aᵢ₋₁ for i > 1.

enum VanishingCoefficients {
  kNone,
  kFirstBVanishes,
  kLastAVanishes,
};

class SRKNIntegrator : public SymplecticIntegrator {
 protected:
  enum VanishingCoefficients {
   kNone,
   kFirstBVanishes,
   kLastAVanishes,
 };

 public:

  // The functors |evolve_kinetic| and |evolve_potential| respectively compute
  // exp(h{·, T})(q, p) given (q, p), and exp(h{·, V})(q, p) given (q, p, t).
  template<typename Position, typename Momentum,
           typename KineticFlow
           typename PotentialFlow>
  void SolveQuadraticKineticEnergy(
      KineticFlow evolve_kinetic,
      PotentialFlow evolve_potential,
      Parameters<Position, Momentum> const& parameters,
      not_null<Solution<Position, Momentum>*> const solution) const;

  // The functor |compute_acceleration| computes M⁻¹ F(q, t).
  template<typename Position, typename Velocity,
           typename RightHandSideComputation>
  void SolveTrivialKineticEnergyIncrement(
      RightHandSideComputation compute_acceleration,
      Parameters<Position, Velocity> const& parameters,
      not_null<Solution<Position, Velocity>*> const solution) const;

 protected:
  struct FirstSameAsLast {
    double first;
    double last;
  };

  VanishingCoefficients vanishing_coefficients_;
  // Null if, and only if, |vanishing_coefficients_ == kNone|.
  // If |vanishing_coefficients_ == kFirstBVanishes|, this contains the first
  // and last a coefficients.
  // If |vanishing_coefficients_ == FirstAVanishes|, this contains the first
  // and last b coefficients.
  // These are used to desynchronize and synchronize first-same-as-last
  // integrators.
  std::unique_ptr<FirstSameAsLast> first_same_as_last_

  int const stages_;

  // The position and momentum nodes.
  // If |vanishing_coefficients_ == kFirstBVanishes|, we do not store the first
  // b coefficient, and the last entry of |a_| is the sum of the first and last
  // a coefficients.
  std::vector<double> a_;
  std::vector<double> b_;

  // The weights.  Note that the first c coefficient is not stored if
  // |vanishing_coefficients_ == kFirstBVanishes|.
  std::vector<double> c_;
 private:
};

}  // namespace integrators
}  // namespace principia

#include "integrators/symplectic_partitioned_runge_kutta_integrator_body.hpp"
<|endoftext|>


<commit_before>#include "catch.hpp"
#include "test-helpers.h"

#include <cache.h>
#include <configcontainer.h>
#include <rss_parser.h>

using namespace newsbeuter;

TEST_CASE("cache behaves correctly") {
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);
	rss_parser parser("file://data/rss.xml", &rsscache, &cfg, nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();
	REQUIRE(feed->total_item_count() == 8);
	rsscache.externalize_rssfeed(feed, false);

	SECTION("items in search result are marked as read") {
		auto search_items = rsscache.search_for_items("Botox", "");
		REQUIRE(search_items.size() == 1);
		auto item = search_items.front();
		REQUIRE(true == item->unread());

		item->set_unread(false);
		search_items.clear();

		search_items = rsscache.search_for_items("Botox", "");
		REQUIRE(search_items.size() == 1);
		auto updatedItem = search_items.front();
		REQUIRE(false == updatedItem->unread());
	}

	std::vector<std::shared_ptr<rss_feed>> feedv;
	feedv.push_back(feed);

	cfg.set_configvalue("cleanup-on-quit", "true");
	rsscache.cleanup_cache(feedv);
}

TEST_CASE("Cleaning old articles works") {
	TestHelpers::TempFile dbfile;
	std::unique_ptr<configcontainer> cfg( new configcontainer() );
	std::unique_ptr<cache> rsscache( new cache(dbfile.getPath(), cfg.get()) );
	rss_parser parser("file://data/rss.xml", rsscache.get(), cfg.get(), nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();

	/* Adding a fresh item that won't be deleted. If it survives the test, we
	 * will know that "keep-articles-days" really deletes the old articles
	 * *only* and not the whole database. */
	auto item = std::make_shared<rss_item>(rsscache.get());
	item->set_title("Test item");
	item->set_link("http://example.com/item");
	item->set_guid("http://example.com/item");
	item->set_author("Newsbeuter Testsuite");
	item->set_description("");
	item->set_pubDate(time(nullptr)); // current time
	item->set_unread(true);
	feed->add_item(item);

	rsscache->externalize_rssfeed(feed, false);

	/* Simulating a restart of Newsbeuter. */

	/* Setting "keep-articles-days" to non-zero value to trigger
	 * cache::clean_old_articles().
	 *
	 * The value of 42 days is sufficient because the items in the test feed
	 * are dating back to 2006. */
	cfg.reset( new configcontainer() );
	cfg->set_configvalue("keep-articles-days", "42");
	rsscache.reset( new cache(dbfile.getPath(), cfg.get()) );
	rss_ignores ign;
	feed = rsscache->internalize_rssfeed("file://data/rss.xml", &ign);

	/* The important part: old articles should be gone, new one remains. */
	REQUIRE(feed->items().size() == 1);
}

TEST_CASE("Last-Modified and ETag values are preserved correctly") {
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);
	const auto feedurl = "file://data/rss.xml";
	rss_parser parser(feedurl, &rsscache, &cfg, nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();
	rsscache.externalize_rssfeed(feed, false);

	/* We will run this lambda on different inputs to check different
	 * situations. */
	auto test = [&](const time_t& lm_value, const std::string& etag_value) {
		time_t last_modified = lm_value;
		std::string etag = etag_value;

		rsscache.update_lastmodified(feedurl, last_modified, etag);
		/* Scrambling the value to make sure the following call changes it. */
		last_modified = 42;
		etag = "42";
		rsscache.fetch_lastmodified(feedurl, last_modified, etag);

		REQUIRE(last_modified == lm_value);
		REQUIRE(etag == etag_value);
	};

	SECTION("Only Last-Modified header was returned") {
		test(1476382350, "");
	}

	SECTION("Only ETag header was returned") {
		test(0, "1234567890");
	}

	SECTION("Both Last-Modified and ETag headers were returned") {
		test(1476382350, "1234567890");
	}
}

TEST_CASE("catchup_all marks all items read") {
	std::shared_ptr<rss_feed> feed, test_feed;

	rss_ignores ign;
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);

	test_feed = std::make_shared<rss_feed>(&rsscache);
	test_feed->set_title("Test feed");
	test_feed->set_link("http://example.com/atom.xml");

	std::vector<std::string> feeds = {
		// { feed's URL, number of items in the feed }
		"file://data/rss.xml",
		"file://data/atom10_1.xml"
	};

	/* Ensure that the feeds contain expected number of items, then externalize
	 * them (put into cache). */
	for (const auto& feedurl : feeds) {
		rss_parser parser(feedurl, &rsscache, &cfg, nullptr);
		feed = parser.parse();

		test_feed->add_item(feed->items()[0]);

		rsscache.externalize_rssfeed(feed, false);
	}

	SECTION("empty feedurl") {
		INFO("All items should be marked as read.");
		rsscache.catchup_all();

		for (const auto& feedurl : feeds) {
			feed = rsscache.internalize_rssfeed(feedurl, &ign);
			for (const auto& item : feed->items()) {
				REQUIRE_FALSE(item->unread());
			}
		}
	}

	SECTION("non-empty feedurl") {
		INFO("All items with particular feedurl should be marked as read");
		rsscache.catchup_all(feeds[0]);

		INFO("First feed should all be marked read");
		feed = rsscache.internalize_rssfeed(feeds[0], &ign);
		for (const auto& item : feed->items()) {
			REQUIRE_FALSE(item->unread());
		}

		INFO("Second feed should all be marked unread");
		feed = rsscache.internalize_rssfeed(feeds[1], &ign);
		for (const auto& item : feed->items()) {
			REQUIRE(item->unread());
		}
	}

	SECTION("actual feed") {
		INFO("All items that are in the specific feed should be marked as read");
		rsscache.catchup_all(test_feed);

		/* Since test_feed contains the first item of each feed, only these two
		 * items should be marked read. */
		auto unread_items_count = [](std::shared_ptr<rss_feed>& feed) {
			unsigned int count = 0;
			for (const auto& item : feed->items()) {
				if (! item->unread()) {
					count++;
				}
			}
			return count;
		};

		feed = rsscache.internalize_rssfeed(feeds[0], &ign);
		REQUIRE(unread_items_count(feed) == 1);

		feed = rsscache.internalize_rssfeed(feeds[1], &ign);
		REQUIRE(unread_items_count(feed) == 1);
	}
}
<commit_msg>Test cache::cleanup_cache<commit_after>#include "catch.hpp"
#include "test-helpers.h"

#include <cache.h>
#include <configcontainer.h>
#include <rss_parser.h>

using namespace newsbeuter;

TEST_CASE("cache behaves correctly") {
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);
	rss_parser parser("file://data/rss.xml", &rsscache, &cfg, nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();
	REQUIRE(feed->total_item_count() == 8);
	rsscache.externalize_rssfeed(feed, false);

	SECTION("items in search result are marked as read") {
		auto search_items = rsscache.search_for_items("Botox", "");
		REQUIRE(search_items.size() == 1);
		auto item = search_items.front();
		REQUIRE(true == item->unread());

		item->set_unread(false);
		search_items.clear();

		search_items = rsscache.search_for_items("Botox", "");
		REQUIRE(search_items.size() == 1);
		auto updatedItem = search_items.front();
		REQUIRE(false == updatedItem->unread());
	}

	std::vector<std::shared_ptr<rss_feed>> feedv;
	feedv.push_back(feed);

	cfg.set_configvalue("cleanup-on-quit", "true");
	rsscache.cleanup_cache(feedv);
}

TEST_CASE("Cleaning old articles works") {
	TestHelpers::TempFile dbfile;
	std::unique_ptr<configcontainer> cfg( new configcontainer() );
	std::unique_ptr<cache> rsscache( new cache(dbfile.getPath(), cfg.get()) );
	rss_parser parser("file://data/rss.xml", rsscache.get(), cfg.get(), nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();

	/* Adding a fresh item that won't be deleted. If it survives the test, we
	 * will know that "keep-articles-days" really deletes the old articles
	 * *only* and not the whole database. */
	auto item = std::make_shared<rss_item>(rsscache.get());
	item->set_title("Test item");
	item->set_link("http://example.com/item");
	item->set_guid("http://example.com/item");
	item->set_author("Newsbeuter Testsuite");
	item->set_description("");
	item->set_pubDate(time(nullptr)); // current time
	item->set_unread(true);
	feed->add_item(item);

	rsscache->externalize_rssfeed(feed, false);

	/* Simulating a restart of Newsbeuter. */

	/* Setting "keep-articles-days" to non-zero value to trigger
	 * cache::clean_old_articles().
	 *
	 * The value of 42 days is sufficient because the items in the test feed
	 * are dating back to 2006. */
	cfg.reset( new configcontainer() );
	cfg->set_configvalue("keep-articles-days", "42");
	rsscache.reset( new cache(dbfile.getPath(), cfg.get()) );
	rss_ignores ign;
	feed = rsscache->internalize_rssfeed("file://data/rss.xml", &ign);

	/* The important part: old articles should be gone, new one remains. */
	REQUIRE(feed->items().size() == 1);
}

TEST_CASE("Last-Modified and ETag values are preserved correctly") {
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);
	const auto feedurl = "file://data/rss.xml";
	rss_parser parser(feedurl, &rsscache, &cfg, nullptr);
	std::shared_ptr<rss_feed> feed = parser.parse();
	rsscache.externalize_rssfeed(feed, false);

	/* We will run this lambda on different inputs to check different
	 * situations. */
	auto test = [&](const time_t& lm_value, const std::string& etag_value) {
		time_t last_modified = lm_value;
		std::string etag = etag_value;

		rsscache.update_lastmodified(feedurl, last_modified, etag);
		/* Scrambling the value to make sure the following call changes it. */
		last_modified = 42;
		etag = "42";
		rsscache.fetch_lastmodified(feedurl, last_modified, etag);

		REQUIRE(last_modified == lm_value);
		REQUIRE(etag == etag_value);
	};

	SECTION("Only Last-Modified header was returned") {
		test(1476382350, "");
	}

	SECTION("Only ETag header was returned") {
		test(0, "1234567890");
	}

	SECTION("Both Last-Modified and ETag headers were returned") {
		test(1476382350, "1234567890");
	}
}

TEST_CASE("catchup_all marks all items read") {
	std::shared_ptr<rss_feed> feed, test_feed;

	rss_ignores ign;
	configcontainer cfg;
	cache rsscache(":memory:", &cfg);

	test_feed = std::make_shared<rss_feed>(&rsscache);
	test_feed->set_title("Test feed");
	test_feed->set_link("http://example.com/atom.xml");

	std::vector<std::string> feeds = {
		// { feed's URL, number of items in the feed }
		"file://data/rss.xml",
		"file://data/atom10_1.xml"
	};

	/* Ensure that the feeds contain expected number of items, then externalize
	 * them (put into cache). */
	for (const auto& feedurl : feeds) {
		rss_parser parser(feedurl, &rsscache, &cfg, nullptr);
		feed = parser.parse();

		test_feed->add_item(feed->items()[0]);

		rsscache.externalize_rssfeed(feed, false);
	}

	SECTION("empty feedurl") {
		INFO("All items should be marked as read.");
		rsscache.catchup_all();

		for (const auto& feedurl : feeds) {
			feed = rsscache.internalize_rssfeed(feedurl, &ign);
			for (const auto& item : feed->items()) {
				REQUIRE_FALSE(item->unread());
			}
		}
	}

	SECTION("non-empty feedurl") {
		INFO("All items with particular feedurl should be marked as read");
		rsscache.catchup_all(feeds[0]);

		INFO("First feed should all be marked read");
		feed = rsscache.internalize_rssfeed(feeds[0], &ign);
		for (const auto& item : feed->items()) {
			REQUIRE_FALSE(item->unread());
		}

		INFO("Second feed should all be marked unread");
		feed = rsscache.internalize_rssfeed(feeds[1], &ign);
		for (const auto& item : feed->items()) {
			REQUIRE(item->unread());
		}
	}

	SECTION("actual feed") {
		INFO("All items that are in the specific feed should be marked as read");
		rsscache.catchup_all(test_feed);

		/* Since test_feed contains the first item of each feed, only these two
		 * items should be marked read. */
		auto unread_items_count = [](std::shared_ptr<rss_feed>& feed) {
			unsigned int count = 0;
			for (const auto& item : feed->items()) {
				if (! item->unread()) {
					count++;
				}
			}
			return count;
		};

		feed = rsscache.internalize_rssfeed(feeds[0], &ign);
		REQUIRE(unread_items_count(feed) == 1);

		feed = rsscache.internalize_rssfeed(feeds[1], &ign);
		REQUIRE(unread_items_count(feed) == 1);
	}
}

TEST_CASE("cleanup_cache behaves as expected") {
	TestHelpers::TempFile dbfile;

	std::vector<std::string> feedurls = {
		"file://data/rss.xml",
		"file://data/atom10_1.xml"
	};

	std::vector<std::shared_ptr<rss_feed>> feeds;
	rss_ignores ign;
	std::unique_ptr<configcontainer> cfg( new configcontainer() );
	std::unique_ptr<cache> rsscache( new cache(dbfile.getPath(), cfg.get()) );
	for (const auto& url : feedurls) {
		rss_parser parser(url, rsscache.get(), cfg.get(), nullptr);
		std::shared_ptr<rss_feed> feed = parser.parse();
		feeds.push_back(feed);
		rsscache->externalize_rssfeed(feed, false);
	}

	SECTION("cleanup-on-quit set to \"no\"") {
		cfg->set_configvalue("cleanup-on-quit", "no");
		rsscache->cleanup_cache(feeds);

		cfg.reset( new configcontainer() );
		rsscache.reset( new cache(dbfile.getPath(), cfg.get()) );

		for (const auto& url : feedurls) {
			std::shared_ptr<rss_feed> feed =
				rsscache->internalize_rssfeed(url, &ign);
			REQUIRE(feed->total_item_count() != 0);
		}
	}

	SECTION("cleanup-on-quit set to \"yes\"") {
		cfg->set_configvalue("cleanup-on-quit", "yes");

		SECTION("delete-read-articles-on-quit set to \"no\"") {
			/* Drop first feed; it should now be removed from the cache, too. */
			feeds.erase(feeds.cbegin(), feeds.cbegin()+1);
			rsscache->cleanup_cache(feeds);

			cfg.reset( new configcontainer() );
			rsscache.reset( new cache(dbfile.getPath(), cfg.get()) );

			std::shared_ptr<rss_feed> feed =
				rsscache->internalize_rssfeed(feedurls[0], &ign);
			REQUIRE(feed->total_item_count() == 0);
			feed = rsscache->internalize_rssfeed(feedurls[1], &ign);
			REQUIRE(feed->total_item_count() != 0);
		}

		SECTION("delete-read-articles-on-quit set to \"yes\"") {
			cfg->set_configvalue("delete-read-articles-on-quit", "yes");
			REQUIRE(feeds[0]->total_item_count() == 8);
			feeds[0]->items()[0]->set_unread(false);
			feeds[0]->items()[1]->set_unread(false);

			rsscache->cleanup_cache(feeds);

			cfg.reset( new configcontainer() );
			rsscache.reset( new cache(dbfile.getPath(), cfg.get()) );

			std::shared_ptr<rss_feed> feed =
				rsscache->internalize_rssfeed(feedurls[0], &ign);
			REQUIRE(feed->total_item_count() == 6);
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Reapply the change from r8062 to fix the Windows Classic maximized window region, which I inexplicably removed in r10845.<commit_after><|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_ERR_CHECK_LESS_OR_EQUAL_HPP
#define STAN_MATH_PRIM_ERR_CHECK_LESS_OR_EQUAL_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err/check_matching_dims.hpp>
#include <stan/math/prim/err/check_matching_sizes.hpp>
#include <stan/math/prim/err/make_iter_name.hpp>
#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/err/throw_domain_error_mat.hpp>
#include <stan/math/prim/err/throw_domain_error_vec.hpp>
#include <stan/math/prim/fun/as_array_or_scalar.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <string>

namespace stan {
namespace math {

/**
 * Check if y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A Scalar
 * @tparam T_high A Scalar
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_stan_scalar_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  check_not_nan(function, name, y);
  check_not_nan(function, "higher", high);
  if (!(y <= high)) {
    [&]() STAN_COLD_PATH {
      std::stringstream msg;
      msg << ", but must be less than ";
      msg << high;
      std::string msg_str(msg.str());
      throw_domain_error(function, name, y, "is ", msg_str.c_str());
    }();
  }
}

/**
 * Check if y is less than each element of high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A Scalar
 * @tparam T_high A type which after calling
 * `as_array_or_scalar(value_of_rec(T_high))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_stan_scalar_t<T_y>* = nullptr,
          require_matrix_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& high_arr = as_array_or_scalar(to_ref(value_of_rec(high)));
  check_not_nan(function, name, y);
  check_not_nan(function, "higher", high_arr);
  for (Eigen::Index j = 0; j < high_arr.cols(); ++j) {
    for (Eigen::Index i = 0; i < high_arr.rows(); ++i) {
      if (!(y <= high_arr.coeff(i, j))) {
        [&high_arr, y, name, function, i, j]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than ";
          msg << high_arr.coeff(i, j);
          std::string msg_str(msg.str());
          throw_domain_error(function, name, y, "is ", msg_str.c_str());
        }();
      }
    }
  }
}

/**
 * Check if each element of y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A type which after calling
 * `as_array_or_scalar(value_of_rec(T_y))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @tparam T_high A Scalar
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_matrix_t<T_y>* = nullptr,
          require_stan_scalar_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& y_arr = as_array_or_scalar(to_ref(value_of_rec(y)));
  check_not_nan(function, name, y_arr);
  check_not_nan(function, "higher", high);
  for (Eigen::Index j = 0; j < y_arr.cols(); ++j) {
    for (Eigen::Index i = 0; i < y_arr.rows(); ++i) {
      if (!(y_arr.coeff(i, j) <= high)) {
        [&y_arr, high, name, function, i, j]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than ";
          msg << high;
          std::string msg_str(msg.str());
          throw_domain_error_mat(function, name, y_arr, i, j, "is ",
                                 msg_str.c_str());
        }();
      }
    }
  }
}

/**
 * Check if each element of y is less than the associated element
 * of high. This function is vectorized and will check each element
 * of y against each element of high.
 * @tparam T_y A type which after calling
 * `as_array_or_scalar(value_of_rec(T_y))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @tparam T_high A type which after calling
 * `as_array_or_scalar(value_of_rec(T_high))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_matrix_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& y_arr = to_ref(as_array_or_scalar(value_of_rec(y)));
  auto&& high_arr = to_ref(as_array_or_scalar(value_of_rec(high)));
  check_not_nan(function, name, y_arr);
  check_not_nan(function, "higher", high_arr);
  if (is_vector<T_y>::value && is_vector<T_high>::value) {
    check_matching_sizes(function, name, y_arr, "higher", high_arr);
    for (Eigen::Index i = 0; i < y_arr.size(); ++i) {
      if (!(y_arr.coeff(i) <= high_arr.coeff(i))) {
        [&y_arr, &high_arr, name, function, i]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than ";
          msg << high_arr.coeff(i);
          std::string msg_str(msg.str());
          throw_domain_error_vec(function, name, y_arr, i, "is ",
                                 msg_str.c_str());
        }();
      }
    }
  } else {
    check_matching_dims(function, name, y_arr, "higher", high_arr);
    for (Eigen::Index j = 0; j < y_arr.cols(); ++j) {
      for (Eigen::Index i = 0; i < y_arr.rows(); ++i) {
        if (!(y_arr.coeff(i, j) <= high_arr.coeff(i, j))) {
          [&y_arr, &high_arr, name, function, i, j]() STAN_COLD_PATH {
            std::stringstream msg;
            msg << ", but must be less than ";
            msg << high_arr.coeff(i, j);
            std::string msg_str(msg.str());
            throw_domain_error_mat(function, name, y_arr, i, j, "is ",
                                   msg_str.c_str());
          }();
        }
      }
    }
  }
}

/**
 * Check if each element of y is less than each associated element
 * of high. This function is vectorized and will check each element
 * of y against each element of high.
 * @tparam T_y A standard vector
 * @tparam T_high Type of upper bound
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_std_vector_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  check_matching_sizes(function, name, y, "higher", high);
  for (size_t i = 0; i < y.size(); ++i) {
    check_less_or_equal(function, internal::make_iter_name(name, i).c_str(),
                        y[i], high[i]);
  }
}

/**
 * Check if each element of y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A standard vector
 * @tparam T_high Type of upper bound
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_std_vector_t<T_y>* = nullptr,
          require_not_std_vector_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  std::string iter_name{name};
  for (size_t i = 0; i < y.size(); ++i) {
    check_less_or_equal(function, internal::make_iter_name(name, i).c_str(),
                        y[i], high);
  }
}

/**
 * Check if y is less than each element of high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A scalar or the same type as the inner type of `T_high`
 * @tparam T_high A standard vector
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_not_std_vector_t<T_y>* = nullptr,
          require_std_vector_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  for (size_t i = 0; i < high.size(); ++i) {
    check_less_or_equal(function, name, y, high[i]);
  }
}
}  // namespace math
}  // namespace stan
#endif
<commit_msg>fix error msg<commit_after>#ifndef STAN_MATH_PRIM_ERR_CHECK_LESS_OR_EQUAL_HPP
#define STAN_MATH_PRIM_ERR_CHECK_LESS_OR_EQUAL_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err/check_matching_dims.hpp>
#include <stan/math/prim/err/check_matching_sizes.hpp>
#include <stan/math/prim/err/make_iter_name.hpp>
#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/err/throw_domain_error_mat.hpp>
#include <stan/math/prim/err/throw_domain_error_vec.hpp>
#include <stan/math/prim/fun/as_array_or_scalar.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <string>

namespace stan {
namespace math {

/**
 * Check if y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A Scalar
 * @tparam T_high A Scalar
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_stan_scalar_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  check_not_nan(function, name, y);
  check_not_nan(function, "higher", high);
  if (!(y <= high)) {
    [&]() STAN_COLD_PATH {
      std::stringstream msg;
      msg << ", but must be less than or equal to";
      msg << high;
      std::string msg_str(msg.str());
      throw_domain_error(function, name, y, "is ", msg_str.c_str());
    }();
  }
}

/**
 * Check if y is less than each element of high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A Scalar
 * @tparam T_high A type which after calling
 * `as_array_or_scalar(value_of_rec(T_high))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_stan_scalar_t<T_y>* = nullptr,
          require_matrix_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& high_arr = as_array_or_scalar(to_ref(value_of_rec(high)));
  check_not_nan(function, name, y);
  check_not_nan(function, "higher", high_arr);
  for (Eigen::Index j = 0; j < high_arr.cols(); ++j) {
    for (Eigen::Index i = 0; i < high_arr.rows(); ++i) {
      if (!(y <= high_arr.coeff(i, j))) {
        [&high_arr, y, name, function, i, j]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than or equal to";
          msg << high_arr.coeff(i, j);
          std::string msg_str(msg.str());
          throw_domain_error(function, name, y, "is ", msg_str.c_str());
        }();
      }
    }
  }
}

/**
 * Check if each element of y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A type which after calling
 * `as_array_or_scalar(value_of_rec(T_y))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @tparam T_high A Scalar
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_matrix_t<T_y>* = nullptr,
          require_stan_scalar_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& y_arr = as_array_or_scalar(to_ref(value_of_rec(y)));
  check_not_nan(function, name, y_arr);
  check_not_nan(function, "higher", high);
  for (Eigen::Index j = 0; j < y_arr.cols(); ++j) {
    for (Eigen::Index i = 0; i < y_arr.rows(); ++i) {
      if (!(y_arr.coeff(i, j) <= high)) {
        [&y_arr, high, name, function, i, j]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than or equal to";
          msg << high;
          std::string msg_str(msg.str());
          throw_domain_error_mat(function, name, y_arr, i, j, "is ",
                                 msg_str.c_str());
        }();
      }
    }
  }
}

/**
 * Check if each element of y is less than the associated element
 * of high. This function is vectorized and will check each element
 * of y against each element of high.
 * @tparam T_y A type which after calling
 * `as_array_or_scalar(value_of_rec(T_y))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @tparam T_high A type which after calling
 * `as_array_or_scalar(value_of_rec(T_high))` returns a type inheriting from
 * EigenBase or a Scalar.
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_matrix_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  auto&& y_arr = to_ref(as_array_or_scalar(value_of_rec(y)));
  auto&& high_arr = to_ref(as_array_or_scalar(value_of_rec(high)));
  check_not_nan(function, name, y_arr);
  check_not_nan(function, "higher", high_arr);
  if (is_vector<T_y>::value && is_vector<T_high>::value) {
    check_matching_sizes(function, name, y_arr, "higher", high_arr);
    for (Eigen::Index i = 0; i < y_arr.size(); ++i) {
      if (!(y_arr.coeff(i) <= high_arr.coeff(i))) {
        [&y_arr, &high_arr, name, function, i]() STAN_COLD_PATH {
          std::stringstream msg;
          msg << ", but must be less than or equal to";
          msg << high_arr.coeff(i);
          std::string msg_str(msg.str());
          throw_domain_error_vec(function, name, y_arr, i, "is ",
                                 msg_str.c_str());
        }();
      }
    }
  } else {
    check_matching_dims(function, name, y_arr, "higher", high_arr);
    for (Eigen::Index j = 0; j < y_arr.cols(); ++j) {
      for (Eigen::Index i = 0; i < y_arr.rows(); ++i) {
        if (!(y_arr.coeff(i, j) <= high_arr.coeff(i, j))) {
          [&y_arr, &high_arr, name, function, i, j]() STAN_COLD_PATH {
            std::stringstream msg;
            msg << ", but must be less than or equal to";
            msg << high_arr.coeff(i, j);
            std::string msg_str(msg.str());
            throw_domain_error_mat(function, name, y_arr, i, j, "is ",
                                   msg_str.c_str());
          }();
        }
      }
    }
  }
}

/**
 * Check if each element of y is less than each associated element
 * of high. This function is vectorized and will check each element
 * of y against each element of high.
 * @tparam T_y A standard vector
 * @tparam T_high Type of upper bound
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_all_std_vector_t<T_y, T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  check_matching_sizes(function, name, y, "higher", high);
  for (size_t i = 0; i < y.size(); ++i) {
    check_less_or_equal(function, internal::make_iter_name(name, i).c_str(),
                        y[i], high[i]);
  }
}

/**
 * Check if each element of y is less than high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A standard vector
 * @tparam T_high Type of upper bound
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high, require_std_vector_t<T_y>* = nullptr,
          require_not_std_vector_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  std::string iter_name{name};
  for (size_t i = 0; i < y.size(); ++i) {
    check_less_or_equal(function, internal::make_iter_name(name, i).c_str(),
                        y[i], high);
  }
}

/**
 * Check if y is less than each element of high.
 * This function is vectorized and will check each element of
 * y against each element of high.
 * @tparam T_y A scalar or the same type as the inner type of `T_high`
 * @tparam T_high A standard vector
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @param high Upper bound
 * @throw domain_error if y is not less than high
 *   or if any element of y or high is NaN.
 */
template <typename T_y, typename T_high,
          require_not_std_vector_t<T_y>* = nullptr,
          require_std_vector_t<T_high>* = nullptr>
inline void check_less_or_equal(const char* function, const char* name,
                                const T_y& y, const T_high& high) {
  for (size_t i = 0; i < high.size(); ++i) {
    check_less_or_equal(function, name, y, high[i]);
  }
}
}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/cache/p9_l2err_linedelete.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///----------------------------------------------------------------------------
///
/// @file p9_l2err_linedelete.C
///
/// @brief Delete the L2 error cache line according to the error extraction
///        information.
///        See more detailed description in header file.
///
/// *HWP HWP Owner   : Chen Qian <qianqc@cn.ibm.com>
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : PRDF
/// *HWP Level       : 3
///----------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_l2err_linedelete.H>
#include <p9_quad_scom_addresses.H>
#include <p9_quad_scom_addresses_fld.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------
const uint32_t BUSY_POLL_DELAY_IN_NS = 10000000; // 10ms
const uint32_t BUSY_POLL_DELAY_IN_CYCLES = 20000000; // 10ms, assumming 2GHz

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------
///
/// @brief  Utility function to check for a purge operation to be completed.
///         This function polls the EX_PRD_PURGE_CMD_REG_BUSY bit of
///         EX_PRD_PURGE_CMD_REG.
///           - If this bit is clear before the input loop threshold is
///             reached, it returns FAPi2_RC_SUCCESS.
///           - Otherwise, it returns an error code.
///
/// @param[in]  i_target          => EX chiplet target
/// @param[in]  i_busyCount       => Max busy count waiting for PURGE to complete.
/// @param[out] o_prdPurgeCmdReg  => EX_PRD_PURGE_CMD_REG value.
///
fapi2::ReturnCode purgeCompleteCheck(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint64_t i_busyCount,
    fapi2::buffer<uint64_t>& o_prdPurgeCmdReg)
{
    FAPI_DBG("Entering purgeCompleteCheck");

    // Wait EX_PRD_PURGE_CMD_REG_BUSY bit for a max input counter time
    uint64_t l_loopCount = 0;

    do
    {
        FAPI_TRY(fapi2::getScom(i_target, EX_PRD_PURGE_CMD_REG, o_prdPurgeCmdReg),
                 "Error from getScom EX_PRD_PURGE_CMD_REG");

        // Check the EX_PRD_PURGE_CMD_REG_BUSY bit from scom register
        if ( !o_prdPurgeCmdReg.getBit(EX_PRD_PURGE_CMD_REG_BUSY) )
        {
            // PURGE is done, get out
            break;
        }
        else
        {
            l_loopCount++;
            // Delay for 10ms
            FAPI_TRY(fapi2::delay(BUSY_POLL_DELAY_IN_NS,
                                  BUSY_POLL_DELAY_IN_CYCLES),
                     "Fapi Delay call failed.");
        }
    }
    while (l_loopCount < i_busyCount);

    // Error out if still busy
    FAPI_ASSERT(l_loopCount < i_busyCount,
                fapi2::P9_L2ERR_LINE_DELETE_REG_BUSY()
                .set_TARGET(i_target)
                .set_COUNT_THRESHOLD(i_busyCount)
                .set_PRD_PURGE_CMD_REG(o_prdPurgeCmdReg),
                "Error: PRD_PURGE_CMD_REG_BUSY exceeds limit count of %d.",
                i_busyCount);

fapi_try_exit:
    FAPI_DBG("Exiting purgeCompleteCheck - Counter: %d; prdPurgeCmdReg: 0x%.16llX",
             l_loopCount, o_prdPurgeCmdReg);
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
// HWP entry point
//------------------------------------------------------------------------------
// See doxygen in header file
// TODO: RTC 178071
// See if with some small refactoring we could just call/share the p9_l2_flush
// HWP code/errors to implement this routine?
fapi2::ReturnCode p9_l2err_linedelete(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const p9_l2err_extract_err_data& i_err_data,
    const uint64_t i_busyCount)
{
    fapi2::buffer<uint64_t> l_l2_l2cerrs_prd_purge_cmd_reg;

    // mark function entry
    FAPI_DBG("Entering p9_l2err_linedelete. BusyCount %d", i_busyCount);

    //   +---------------------------+
    //   |    L2 Line Delete Scom    |
    //   +---------------------------+
    //   |Bit(s)|  Data              |
    //   +------+--------------------+
    //   |    0 | Trigger            |
    //   +------+--------------------+
    //   |  1:4 | Purge type (LD=0x2)|
    //   +------+--------------------+
    //   | 5:16 | Don't care         |
    //   +------+--------------------+
    //   |17:19 | Member             |
    //   +------+--------------------+
    //   |20:27 | CGC  addr 48:55    |
    //   +------+--------------------+
    //   |   28 | Bank               |
    //   +------+--------------------+
    //   |29:30 | Don't care         |
    //   +------+--------------------+

    // Write member, address and bank into PRD Purge Engine Command Register
    // SCOM Addr: 0x000000001001080E
    // bit 0 is the trigger, the act of writing this bit to 1 sets off the line delete
    // bits 1:4 is ttype 0b0010 = line delete
    // bits 17:19 is the member
    // bits 20:27 is the cgc address
    // bit 28 is the bank

    // Make sure there's no current purge is in progress
    FAPI_TRY(purgeCompleteCheck(i_target, i_busyCount,
                                l_l2_l2cerrs_prd_purge_cmd_reg),
             "Error returned from purgeCompleteCheck()");
    FAPI_DBG("l_l2_l2cerrs_prd_purge_cmd_reg_data: 0x%.16llX",
             l_l2_l2cerrs_prd_purge_cmd_reg);

    // write trigger, type, cgc address and bank into PRD Purge Engine Command Register
    l_l2_l2cerrs_prd_purge_cmd_reg.insertFromRight
    <EX_PRD_PURGE_CMD_REG_MEM, EX_PRD_PURGE_CMD_REG_MEM_LEN>
    (i_err_data.member);
    l_l2_l2cerrs_prd_purge_cmd_reg.insertFromRight
    <EX_PRD_PURGE_CMD_REG_CGC, EX_PRD_PURGE_CMD_REG_CGC_LEN>
    (i_err_data.address);
    l_l2_l2cerrs_prd_purge_cmd_reg.insertFromRight
    <EX_PRD_PURGE_CMD_REG_BANK, 1>(i_err_data.bank);

    l_l2_l2cerrs_prd_purge_cmd_reg.insertFromRight
    <EX_PRD_PURGE_CMD_REG_TRIGGER, 1>(1);
    l_l2_l2cerrs_prd_purge_cmd_reg.insertFromRight
    <EX_PRD_PURGE_CMD_REG_TYPE, EX_PRD_PURGE_CMD_REG_TYPE_LEN>(0x2);

    FAPI_DBG("l_l2_l2cerrs_prd_purge_cmd_reg_data: %#lx",
             l_l2_l2cerrs_prd_purge_cmd_reg);
    FAPI_TRY(fapi2::putScom(i_target, EX_PRD_PURGE_CMD_REG,
                            l_l2_l2cerrs_prd_purge_cmd_reg),
             "Error from putScom EX_PRD_PURGE_CMD_REG");

    // Verify purge operation is complete
    FAPI_TRY(purgeCompleteCheck(i_target, i_busyCount,
                                l_l2_l2cerrs_prd_purge_cmd_reg),
             "Error returned from purgeCompleteCheck()");
    FAPI_DBG("l_l2_l2cerrs_prd_purge_cmd_reg_data: 0x%.16llX",
             l_l2_l2cerrs_prd_purge_cmd_reg);

fapi_try_exit:
    FAPI_INF("Exiting p9_l2err_linedelete...");
    return fapi2::current_err;
} // p9_l2err_extract
<commit_msg>Share common code between p9_l2_flush and p9_l2err_linedelete<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/cache/p9_l2err_linedelete.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///----------------------------------------------------------------------------
///
/// @file p9_l2err_linedelete.C
///
/// @brief Delete the L2 error cache line according to the error extraction
///        information.
///        See more detailed description in header file.
///
/// *HWP HWP Owner   : Chen Qian <qianqc@cn.ibm.com>
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : PRDF
/// *HWP Level       : 3
///----------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_l2err_linedelete.H>
#include <p9_l2_flush.H>
#include <p9_quad_scom_addresses.H>
#include <p9_quad_scom_addresses_fld.H>

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// HWP entry point
//------------------------------------------------------------------------------
// See doxygen in header file
fapi2::ReturnCode p9_l2err_linedelete(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const p9_l2err_extract_err_data& i_err_data,
    const uint64_t i_busyCount)
{
    fapi2::ReturnCode l_rc;
    fapi2::buffer<uint64_t> l_cmdReg;
    p9core::purgeData_t l_purgeData;

    // mark function entry
    FAPI_DBG("Entering p9_l2err_linedelete. BusyCount %d", i_busyCount);

    //   +---------------------------+
    //   |    L2 Line Delete Scom    |
    //   +---------------------------+
    //   |Bit(s)|  Data              |
    //   +------+--------------------+
    //   |    0 | Trigger            |
    //   +------+--------------------+
    //   |  1:4 | Purge type (LD=0x2)|
    //   +------+--------------------+
    //   | 5:16 | Don't care         |
    //   +------+--------------------+
    //   |17:19 | Member             |
    //   +------+--------------------+
    //   |20:27 | CGC  addr 48:55    |
    //   +------+--------------------+
    //   |   28 | Bank               |
    //   +------+--------------------+
    //   |29:30 | Don't care         |
    //   +------+--------------------+

    // Write member, address and bank into PRD Purge Engine Command Register
    // SCOM Addr: 0x000000001001080E
    // bit 0 is the trigger, the act of writing this bit to 1 sets off the line delete
    // bits 1:4 is ttype 0b0010 = line delete
    // bits 17:19 is the member
    // bits 20:27 is the cgc address
    // bit 28 is the bank

    // Ensure that purge engine is idle before starting line delete
    FAPI_TRY(purgeCompleteCheck(i_target, i_busyCount, l_cmdReg),
             "Error returned from purgeCompleteCheck call");

    // Set PRD Purge Engine Command register values for line delete
    l_purgeData.iv_cmdType = 0b0010; // L2 Dir Line_Delete
    l_purgeData.iv_cmdMem = i_err_data.member;
    l_purgeData.iv_cmdBank = i_err_data.bank;
    l_purgeData.iv_cmdCGC = i_err_data.address;

    FAPI_TRY(setupAndTriggerPrdPurge(i_target, l_purgeData, l_cmdReg),
             "Error returned from setupAndTriggerPrdPurge");

    // Verify purge/line delete complete
    FAPI_TRY(purgeCompleteCheck(i_target, i_busyCount, l_cmdReg),
             "Error returned from purgeCompleteCheck call");

fapi_try_exit:
    FAPI_INF("Exiting p9_l2err_linedelete...");
    return fapi2::current_err;
} // p9_l2err_extract
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_DETAIL_EVENTLOOP_HXX_
#define _QI_DETAIL_EVENTLOOP_HXX_

#include <qi/detail/future_fwd.hpp>
#include <qi/actor.hpp>

namespace qi
{

template <typename R>
void nullConverter(void*, R&)
{}

template <typename R>
Future<R> EventLoop::async(const boost::function<R()>& callback,
                                  uint64_t usDelay)
{
  return async(callback, qi::MicroSeconds(usDelay));
}

namespace detail
{
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::Duration delay) ->
      typename std::enable_if<detail::IsAsyncBind<F>::value, typename std::decay<decltype(cb())>::type>::type
  {
    if (delay != qi::Duration::zero())
      return qi::getEventLoop()->asyncDelay(cb, delay).unwrap();
    else
      return cb();
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::Duration delay) ->
      typename std::enable_if<!detail::IsAsyncBind<F>::value,
               qi::Future<typename std::decay<decltype(cb())>::type>>::type
  {
    return qi::getEventLoop()->asyncDelay(cb, delay);
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::SteadyClockTimePoint timepoint) ->
      typename std::enable_if<detail::IsAsyncBind<F>::value, typename std::decay<decltype(cb())>::type>::type
  {
    return qi::getEventLoop()->asyncAt(cb, timepoint).unwrap();
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::SteadyClockTimePoint timepoint) ->
      typename std::enable_if<!detail::IsAsyncBind<F>::value,
               qi::Future<typename std::decay<decltype(cb())>::type>>::type
  {
    return qi::getEventLoop()->asyncAt(cb, timepoint);
  }

  // sfinae to try to call unwrap on the future
  template <typename F>
  auto tryUnwrap(const F& future, int) -> decltype(future.unwrap())
  {
    return future.unwrap();
  }
  template <typename F>
  F tryUnwrap(const F& future, void*)
  {
    return future;
  }

  // this function is used by qilang generation to call something regardless of if it's an actor or not
  // it is very specific to qilang's generated code, I don't think it's a good idea to use it elsewhere
  // this function may or may not return a future (the other overload does not)
  template <typename F, typename Arg0, typename... Args>
  auto invokeMaybeActor(F&& cb, Arg0* arg0, Args&&... args) ->
      typename std::enable_if<std::is_base_of<Actor, typename std::decay<Arg0>::type>::value,
               decltype(tryUnwrap(qi::async(qi::bind(cb, arg0, std::forward<Args>(args)...)), 0))>::type
  {
    // this is an actor, we must async to strand the call
    return tryUnwrap(qi::async(qi::bind(cb, arg0, std::forward<Args>(args)...)), 0);
  }
  template <typename F, typename Arg0, typename... Args>
  auto invokeMaybeActor(F&& cb, Arg0* arg0, Args&&... args) ->
      typename std::enable_if<!std::is_base_of<Actor, typename std::decay<Arg0>::type>::value,
               typename std::decay<decltype((arg0->*cb)(std::forward<Args>(args)...))>::type>::type
  {
    return (arg0->*cb)(std::forward<Args>(args)...);
  }
}

}

#endif
<commit_msg>Future: tryUnwrap to prefer universal references<commit_after>#pragma once
/*
**  Copyright (C) 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QI_DETAIL_EVENTLOOP_HXX_
#define _QI_DETAIL_EVENTLOOP_HXX_

#include <qi/detail/future_fwd.hpp>
#include <qi/actor.hpp>

namespace qi
{

template <typename R>
void nullConverter(void*, R&)
{}

template <typename R>
Future<R> EventLoop::async(const boost::function<R()>& callback,
                                  uint64_t usDelay)
{
  return async(callback, qi::MicroSeconds(usDelay));
}

namespace detail
{
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::Duration delay) ->
      typename std::enable_if<detail::IsAsyncBind<F>::value, typename std::decay<decltype(cb())>::type>::type
  {
    if (delay != qi::Duration::zero())
      return qi::getEventLoop()->asyncDelay(cb, delay).unwrap();
    else
      return cb();
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::Duration delay) ->
      typename std::enable_if<!detail::IsAsyncBind<F>::value,
               qi::Future<typename std::decay<decltype(cb())>::type>>::type
  {
    return qi::getEventLoop()->asyncDelay(cb, delay);
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::SteadyClockTimePoint timepoint) ->
      typename std::enable_if<detail::IsAsyncBind<F>::value, typename std::decay<decltype(cb())>::type>::type
  {
    return qi::getEventLoop()->asyncAt(cb, timepoint).unwrap();
  }
  template <typename F>
  auto asyncMaybeActor(F&& cb, qi::SteadyClockTimePoint timepoint) ->
      typename std::enable_if<!detail::IsAsyncBind<F>::value,
               qi::Future<typename std::decay<decltype(cb())>::type>>::type
  {
    return qi::getEventLoop()->asyncAt(cb, timepoint);
  }

  // sfinae to try to call unwrap on the future
  template <typename F>
  auto tryUnwrap(F&& future, int) -> decltype(future.unwrap())
  {
    return future.unwrap();
  }
  template <typename F>
  F tryUnwrap(F&& future, void*)
  {
    return std::forward<F>(future);
  }

  // this function is used by qilang generation to call something regardless of if it's an actor or not
  // it is very specific to qilang's generated code, I don't think it's a good idea to use it elsewhere
  // this function may or may not return a future (the other overload does not)
  template <typename F, typename Arg0, typename... Args>
  auto invokeMaybeActor(F&& cb, Arg0* arg0, Args&&... args) ->
      typename std::enable_if<std::is_base_of<Actor, typename std::decay<Arg0>::type>::value,
               decltype(tryUnwrap(qi::async(qi::bind(cb, arg0, std::forward<Args>(args)...)), 0))>::type
  {
    // this is an actor, we must async to strand the call
    return tryUnwrap(qi::async(qi::bind(cb, arg0, std::forward<Args>(args)...)), 0);
  }
  template <typename F, typename Arg0, typename... Args>
  auto invokeMaybeActor(F&& cb, Arg0* arg0, Args&&... args) ->
      typename std::enable_if<!std::is_base_of<Actor, typename std::decay<Arg0>::type>::value,
               typename std::decay<decltype((arg0->*cb)(std::forward<Args>(args)...))>::type>::type
  {
    return (arg0->*cb)(std::forward<Args>(args)...);
  }
}

}

#endif
<|endoftext|>