C++ Boost.Graph-algo.is_optimal()断言

C++ Boost.Graph-algo.is_optimal()断言,c++,boost,boost-graph,C++,Boost,Boost Graph,我正在尝试实现一个程序,使用最小成本流算法检测机会。该算法在Boost.Graph中以Boost::push\u relabel\u max\u flow()的形式实现,然后调用Boost::cycle\u canceling() 以下是我已经拥有的代码,省略了boost::cycle\u canceling-部分,因为我的程序在到达函数之前就死了 #include <boost/graph/adjacency_list.hpp> #include <boost

我正在尝试实现一个程序,使用最小成本流算法检测机会。该算法在Boost.Graph中以
Boost::push\u relabel\u max\u flow()
的形式实现,然后调用
Boost::cycle\u canceling()

以下是我已经拥有的代码,省略了
boost::cycle\u canceling
-部分,因为我的程序在到达函数之前就死了

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/property_map/property_map.hpp>
    #include <boost/graph/push_relabel_max_flow.hpp>
    #include <boost/graph/cycle_canceling.hpp>
    #include <boost/graph/directed_graph.hpp>
    #include <boost/config.hpp>
    #include <iostream>
    #include <string>



    typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;

    struct st_order {
        double price;
        double amount;
        std::string type;
    };

    struct VertexProps {
        unsigned int id;
    };

    struct EdgeProps {
        double capacity;
        double residual_capacity;
        double weight;
        Traits::edge_descriptor reverse;
    };

    typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps > DirectedGraph;

    int main() {


        DirectedGraph g;

        // ETH / BTC
        std::vector<st_order> trades{
            st_order{0.0101,10.0,"SELL"},
            st_order{0.01,3.0,"BUY"},
            st_order{0.0102,5.0,"SELL"},
            st_order{0.2,42.0,"BUY"},
        };


        std::vector<boost::graph_traits<DirectedGraph>::vertex_descriptor> vertices;
        for(unsigned int vertex_index = 0; vertex_index < trades.size(); vertex_index++)
        {
            vertices.push_back(boost::add_vertex({vertex_index}, g));
        }


        std::map<DirectedGraph::vertex_descriptor, std::map<DirectedGraph::vertex_descriptor, Traits::edge_descriptor>> edges;


int ifirst = 0;
for(auto& first : vertices)
{
    int isecond = 0;
    for(auto& second : vertices)
    {

        if(first == second || trades[ifirst].type.compare(trades[isecond].type) == 0)
        {
            isecond++;
            continue;
        }

        double amount = trades[isecond].amount;

        if(trades[isecond].type.compare("SELL") == 0)
            amount = amount * trades[isecond].price;

        edges[first][second] = boost::add_edge(first, second, {amount, amount, (trades[isecond].price / trades[ifirst].price)} , g).first;
        std::cout << "Add Edge: From " << first << " to " << second << std::endl;

        isecond++;
    }
    ifirst++;
}


for(auto& i : vertices)
{
    for(auto& j : vertices)
    {
        if(i == j)
            continue;

        if(edges.find(i) != edges.end() && edges[i].find(j) != edges[i].end())
        {
            if(edges.find(j) == edges.end() || edges[j].find(i) == edges[j].end())
            {
                throw std::runtime_error("No return edge found: "+std::to_string(i)+" "+std::to_string(j));
            }

            auto edge = boost::edge(i,j,g).first;
            g[edge].reverse = edges[i][j];

        }
    }
}



        double flow = boost::push_relabel_max_flow(g, vertices[0], vertices[1],
                boost::get(&EdgeProps::capacity, g),
                boost::get(&EdgeProps::residual_capacity, g),
                boost::get(&EdgeProps::reverse, g),
                boost::get(boost::vertex_index, g)
            );

// Now boost::cycle_canceling() would follow

    std::cout << "END << std::endl;
    return 0;
    };
如流程图所示:

我的程序在
push\u relabel\u max\u flow
函数中断言。以下是完整的错误代码(在运行时打印):

我在谷歌上搜索了一下,什么也没找到。我是否以错误的方式传递参数?是否因为我使用了
double
作为容量(尽管,如果我没有记错的话,“”描述了使用
double
作为容量是可能的)? 此外,我还发现了以下句子:

CapacityEdgeMap参数cap必须将E中的每条边映射为正数 编号,和E^T中的每一条边到0


粗体部分是什么意思?这是否意味着我必须将汇顶点的所有输出边的容量设置为0?

您需要将反向边的容量设置为0

因此,您需要:

auto edge = boost::edge(i,j,g).first;
g[edge].reverse = edges[i][j];
g[edges[i][j]].capacity = 0;
我不知道为什么会这样。我注意到,它们创建了它们的反向边,并为它们提供了0容量。大约在页面下方的3/4处:

capacity[e1] = cap;
capacity[e2] = 0;
reverse_edge[e1] = e2;
reverse_edge[e2] = e1;
如果没有此约束,算法将尝试将这些边视为法线边。您引用的文档部分对此进行了描述,但并不完全清楚

对输入图形和属性有一些特殊要求 映射此算法的参数。首先,有向图G=(V,E) 表示网络的,必须扩充以包含反向 E中每条边的边。也就是说,输入图形应为Gin= (V,{E U E^T})。ReverseEdgeMap参数rev必须映射中的每条边 将原始图形还原到其反向边,即(u,v)->(v,u)表示所有 (u,v)在E中。CapacityEdge参数cap必须映射E中的每条边 为正数,E^T中的每条边为0

我想这里E^T的意思是转置而不是目标。你们必须知道,有向邻接矩阵的转置实际上是所有边的倒数。这就是为什么他们说输入图是G={V,eue^T}。边加上需要添加的反向边


旁注:将中的
long
更改为
double
效果非常好。

我不熟悉这个特定的算法。虽然我运行了你的代码,但它看起来是最佳的,它是push-relabel算法的一部分,而不是我最初认为的boost。我猜这可能与图形的拓扑结构有关。我没时间看你的图形生成代码。您确定此拓扑对于此类问题是正确的吗?你可以考虑用这个算法的最小工作例子来凝视。我用更多的信息和图表编辑了我的文章。我很确定我可以在我的图中使用这个算法。
bool is_optimal() {
        // check if mincut is saturated...
        global_distance_update();
        return get(distance, src) >= n;
      }
auto edge = boost::edge(i,j,g).first;
g[edge].reverse = edges[i][j];
g[edges[i][j]].capacity = 0;
capacity[e1] = cap;
capacity[e2] = 0;
reverse_edge[e1] = e2;
reverse_edge[e2] = e1;