// -*- C++ -*-

/*!
  \file numerical/random/discrete/DgPmf.h
  \brief Probability mass function for a discrete generator.
*/

#if !defined(__numerical_DgPmf_h__)
#define __numerical_DgPmf_h__

#include "../../../ext/vector.h"

#include <limits>

namespace numerical {

//! Probability mass function for a discrete generator.
/*!
  Manage the probability mass function.
*/
template<bool _Guarded>
class DgPmf {
   //
   // Protected types.
   //
protected:

   //! The number type.
   typedef double Number;
   //! The array type.
   typedef std::vector<Number> Container;
   //! Const iterator.
   typedef Container::const_iterator const_iterator;
   //! Iterator.
   typedef Container::iterator iterator;

   //
   // Member data.
   //
protected:

   //! Probability mass function.  (This is scaled and may not sum to unity.)
   Container _pmf;

   //--------------------------------------------------------------------------
   //! \name Constructors etc.
   //@{
protected:

   //! Default constructor.
   DgPmf() :
      // The PMF array is empty.
      _pmf(std::size_t(_Guarded)) {
      if (_Guarded) {
         // The guard element.
         _pmf.back() = 0.5 * std::numeric_limits<Number>::max();
      }
   }

   //! Copy constructor.
   DgPmf(const DgPmf& other) :
      _pmf(other._pmf) {}

   //! Assignment operator.
   DgPmf&
   operator=(const DgPmf& other) {
      if (this != &other) {
         _pmf = other._pmf;
      }
      return *this;
   }

   //! Destructor.
   ~DgPmf() {}

   //@}
   //--------------------------------------------------------------------------
   //! \name Accessors.
   //@{
protected:

   //! Get the probability with the specified index.
   Number
   operator[](const std::size_t i) const {
      return _pmf[i];
   }

   //! Get the beginning of the PMF.
   const_iterator
   begin() const {
      return _pmf.begin();
   }

   //! Get the end of the PMF.
   const_iterator
   end() const {
      return _pmf.end() - _Guarded;
   }

   //! Get the number of possible deviates.
   std::size_t
   size() const {
      return _pmf.size() - _Guarded;
   }

   //@}
   //--------------------------------------------------------------------------
   //! \name Equality.
   //@{
protected:

   bool
   operator==(const DgPmf& other) const {
      return _pmf == other._pmf;
   }

   //@}
   //--------------------------------------------------------------------------
   //! \name Manipulators.
   //@{
protected:

   //! Get the beginning of the value/index pairs.
   iterator
   begin() {
      return _pmf.begin();
   }

   //! Get the end of the value/index pairs.
   iterator
   end() {
      return _pmf.end() - _Guarded;
   }

   //! Set the probability mass function with the specified index.
   void
   set(std::size_t index, Number value) {
      _pmf[index] = value;
   }

#if 0
   //! Set the probability mass functions.
   template<typename _RandomAccessIterator>
   void
   set(_RandomAccessIterator iterator) {
      for (std::size_t i = 0; i != _pmf.size(); ++i) {
         _pmf[i] = iterator[i];
      }
   }
#endif

   //! Initialize the probability mass function.
   template<typename ForwardIterator>
   void
   initialize(ForwardIterator begin, ForwardIterator end) {
      _pmf.resize(std::distance(begin, end) + _Guarded);
      if (_Guarded) {
         // The guard element.
         _pmf.back() = 0.5 * std::numeric_limits<Number>::max();
      }
      std::copy(begin, end, _pmf.begin());
   }

   //@}
   //--------------------------------------------------------------------------
   //! \name File I/O.
   //@{
protected:

   //! Print information about the data structure.
   void
   print(std::ostream& out) const {
      out << "PMF = \n" << _pmf << '\n';
   }

   //@}
};

} // namespace numerical

#endif
