c++ - boost :任意分布的 vector

标签 c++ boost vector distribution boost-any

尊敬的 Stack Exchange 专家,

我正在尝试建立一个类(多变量分布函数),将 boost 分布存储在 std::vector(边际分布函数)中。 虽然这可以使用 boost::variant(参见我的问题:Boost: Store Pointers to Distributions in Vector),但我也尝试了 boost::any。 原因是对于变体,我必须在设置变体时对潜在类型(边际分布)进行硬编码,而我想避免这种情况。

虽然不同的实现分布类不共享一个公共(public)父类,但有一些函数,如 boost::math::cdf 或 boost::math::pdf 可以应用于所有分布,我想在 std::vector 上应用迭代。

使用 any 我生成了下面的代码(运行良好),但现在我遇到了函数 any_cdf 需要检查类型的问题。

虽然我在设置 vector 时绕过了对类型进行硬编码(对于变体),但我现在需要在 any_cdf 函数中对类型进行硬编码(而具有变体的解决方案可以通过模板化访问者函数,因此没有任何类型规范),这意味着需要管理大量代码,大量 if 语句...

但是,逻辑根本没有改变(我强制转换类型,然后在所有 if 语句中应用 cdf 函数),如果存储在 boost 分布之外的其他内容,我不会真正关心函数的行为方式列表。

那么有没有机会吃我的蛋糕并吃掉它,这意味着不被迫在 any_cdf 中硬编码分布的转换类型(很像变体的模板化访问者函数)?

非常感谢你的帮助,H。

附言如果这不可行,在这种情况下我通常会更好地使用 boost::any 或 boost::variant 吗?

#include <boost/math/distributions.hpp>
#include <boost/any.hpp>
#include <vector>
#include <iostream>
#include <limits>

//template function to apply cdf
template<class T> T any_cdf(boost::any a, T &x){

    //declare return value
    T y;

    //cast any with hardcoded types
    if (a.type() == typeid(boost::math::normal_distribution<T>)){

    y = boost::math::cdf(boost::any_cast< boost::math::normal_distribution<T> >(a),x);

    } else if (a.type() == typeid(boost::math::students_t_distribution<T>)){

    y = boost::math::cdf(boost::any_cast< boost::math::students_t_distribution<T> >(a), x);

    } else {
    //return NaN in case of failure or do something else (throw exception...)
    y =  std::numeric_limits<T>::quiet_NaN();
    }

    return(y);
}



int main (int, char*[])
{
    //get distribution objects
    boost::math::normal_distribution<double> s;
    boost::math::students_t_distribution<double> t(1);

    //use any to put just any kind of objects in one vector 
    std::vector<boost::any> vec_any;
    vec_any.push_back(s);
    vec_any.push_back(t);

    //evaluation point and return value 
    double y;
    double x = 1.96;

    for (std::vector<boost::any>::const_iterator iter = vec_any.begin(); iter != vec_any.end(); ++iter){

        y = any_cdf<double>(*iter,x);
        std::cout << y << std::endl;

    }

    return 0;
}

编辑:关于评论,任何似乎都不是手头任务的最简单/最佳选择。然而,出于完整性原因,访问者喜欢 boost::any 的实现在以下位置进行了讨论: visitor pattern for boost::any

最佳答案

Note See my older answer for a discussion of solutions a vector and boost::any vs. boost::variant.

如果您实际上不需要分布的动态 vector - 但只想应用静态已知的分布列表,您可以使用 tuple<> “逃脱”

现在,借助 Phoenix 和 Fusion 的一些(嗯,很多)魔法,您可以“只”调整 cdf作为一个懒惰的 Actor :

BOOST_PHOENIX_ADAPT_FUNCTION(double, cdf_, boost::math::cdf, 2)

在这种情况下,一个等效 extended代码示例缩小为:查看 Live On Coliru

int main()
{
    typedef boost::tuple<bm::normal, bm::students_t> Dists;
    Dists dists(bm::normal(), bm::students_t(1));

    double x = 1.96;

    boost::fusion::for_each(dists, std::cout << cdf_(arg1, x) << "\n");

    std::cout << "\nComposite (multiplication):\t" << boost::fusion::accumulate(dists, 1.0, arg1 * cdf_(arg2, x));
    std::cout << "\nComposite (mean):\t\t"         << boost::fusion::accumulate(dists, 0.0, arg1 + cdf_(arg2, x)) / boost::tuples::length<Dists>::value;
}

哇哦。那是……不到 6 行代码 :) 最好的部分是它已经完全兼容 c++03

关于c++ - boost :任意分布的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22666108/

相关文章:

c++ - 使用运算符重载添加到列表

c++ - 将设备 vector 乘以常数

javascript - 如何从一个 QtScript .js 文件调用另一个 QtScript .js 文件

c++ - 在 constexpr 中使用 boost 数学常量

c++ - 找不到 boost_process cmake find_package

c++ - boost-sprit-lex 将多个标记统一为 lex 中由 id 区分的单个标记

c++ - 我的虚函数无法工作 C++

c++ - std::move(std::unique_ptr()) 组合是否有标准缩写?

c++ - 为什么在实践中向右移动在 Neon 和 SSE 中向左移动(反之亦然)?

c++ - Qt 如何从运行的线程更新主窗口,正确的方法