Program Listing for File PDFReflect.hpp

↰ Return to documentation for file (src/pdfs/PDFReflect.hpp)

#ifndef PDFREFLECT_HPP
#define PDFREFLECT_HPP

#include "PDF.hpp"
#include <functional>
#include <limits>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>

namespace pdfs {

    class PDFReflect : public PDF {
    public:

        // Un-hide PDF::integral()'s no-argument overload: declaring
        // integral(a, b) below would otherwise hide every base-class
        // overload of the name "integral" in this class's scope, per
        // ordinary C++ name-hiding rules, even though the no-argument
        // form needs no change (see integral(a,b)'s own comment).
        using PDF::integral;

        [[nodiscard]] auto toToml() const -> std::string override
        {
            throw std::logic_error("PDFReflect::toToml: a reflected view of a PDF "
                "cannot be serialized; serialize the PDF it wraps instead");
        }

        explicit PDFReflect(const PDF& pdf) :
            PDFReflect(pdf, 0.5 * (pdf.getMin() + pdf.getMax()))
        { }

        PDFReflect(const PDF& pdf, const double pivot) :
            pdf_(std::cref(pdf)),
            pivot_(pivot)
        {
            sMin_ = pdf.getMin();
            sMax_ = pdf.getMax();
            wgt_ = pdf.getWeights();
        }

        auto operator()(double x) const -> double override
        {
            return pdf_.get()(reflect(x));
        }

        [[nodiscard]] auto expectationValue() const -> double override
        {
            return reflect(pdf_.get().expectationValue());
        }

        [[nodiscard]] auto deltas() const -> std::vector<std::pair<double, double>> override
        {
            auto result = pdf_.get().deltas();
            for (auto& [x, w] : result) { x = reflect(x); }
            return result;
        }

        [[nodiscard]] auto expectationValue(const double a, const double b) const -> double override
        {
            const double aReflect = reflect(b);
            const double bReflect = reflect(a);
            return reflect(pdf_.get().expectationValue(aReflect, bReflect));
        }

        [[nodiscard]] auto integral(const double a, const double b) const -> double override
        {
            const double aReflect = reflect(b);
            const double bReflect = reflect(a);
            return pdf_.get().integral(aReflect, bReflect);
        }

        [[nodiscard]]
        auto draw(const double a = std::numeric_limits<double>::lowest(),
            const double b = std::numeric_limits<double>::max()) const -> double override
        {
            const double aReflect = reflect(b);
            const double bReflect = reflect(a);
            return reflect(pdf_.get().draw(aReflect, bReflect));
        }

        [[nodiscard]] auto draw(unsigned int nDraw,
            double a = std::numeric_limits<double>::lowest(),
            double b = std::numeric_limits<double>::max())
            const -> std::vector<double> override
        {
            const double aReflect = reflect(b);
            const double bReflect = reflect(a);
            auto result = pdf_.get().draw(nDraw, aReflect, bReflect);
            for (auto& r : result) { r = reflect(r); }
            return result;
        }

        [[nodiscard]] auto drawTarget(double target,
            double a = std::numeric_limits<double>::lowest(),
            double b = std::numeric_limits<double>::max()) const
            -> std::vector<double> override
        {
            const double aReflect = reflect(b);
            const double bReflect = reflect(a);
            auto result = pdf_.get().drawTarget(target, aReflect, bReflect);
            for (auto& r : result) { r = reflect(r); }
            return result;
        }

    private:

        [[nodiscard]] auto reflect(const double x) const -> double
        {
            return (2.0 * pivot_) - x;
        }

        std::reference_wrapper<const PDF> pdf_;
        double pivot_;
    };

} // namespace pdfs

#endif // PDFREFLECT_HPP