繁体   English   中英

通过Boost Graph库C++实现拍卖算法

[英]Implementation of Auction Algorthm via Boost Graph Library C++

正如我在上一个问题中引用的:

我正在研究一个应用程序基准,该基准比较了提升最大加权匹配拍卖算法在解决二部图分配问题方面的运输问题的性能。

目前我已经使用 boost 图形库的捆绑特性实现了一个拍卖算法的版本,这个实现的灵感来自github的矢量版本。 我这样做是为了将两种算法置于同一水平,以做出公平的基准。 这里是:

#include "../include/Auction.h"
#include "../include/BipartiteGraph.h"

void auction_algorithm(Graph& graph, const int& n, duration& elapsed) {
    const Weight eps = 1;
    int unassigned_bidders = n;
    GraphProp& gp = graph[boost::graph_bundle];

    EdgeFilter any_interconnect = boost::keep_all{};
    VertexFilter bidders = [graph](V v) -> bool { return boost::get<Bidder>(&(graph)[v]); };
    VertexFilter items = [graph](V v) -> bool { return boost::get<Item>(&(graph)[v]); };

    FMap map_bidders = FMap(graph, any_interconnect, bidders);
    FMap map_items = FMap(graph, any_interconnect, items);    
    
    auto iterator_bidder = boost::make_iterator_range(boost::vertices(map_bidders));
    auto iterator_item = boost::make_iterator_range(boost::vertices(map_items));
    auto t_start = now();

    while (unassigned_bidders > 0) {

        for (auto uncasted_bidder : iterator_bidder) {
            if (gp.bidder2item[static_cast<int>(uncasted_bidder)] != -1) continue;
            Bidder* bidder = boost::get<Bidder>(&graph[uncasted_bidder]);

            
            // 1 Bid

            int id_item1 = -1;
            Weight val_item1 = -1;
            Weight val_item2 = -1;

            for (auto uncasted_item : iterator_item) {
                Item* item = boost::get<Item>(&graph[static_cast<int>(uncasted_item)]);
                Weight val = boost::get(boost::edge_weight_t(), graph, (boost::edge(uncasted_bidder, uncasted_item, graph)).first) - item->cost;

                if (val > val_item1) {
                    val_item2 = val_item1;
                    val_item1 = val;
                    id_item1 = item->id;
                }
                else if (val > val_item2) {
                    val_item2 = val;
                }
            }

            bidder->best_item = id_item1 + n;
            bidder->val_first_best_item = val_item1;
            bidder->val_second_best_item = val_item2;


            // 2 Compete

            Weight bid = bidder->val_first_best_item - bidder->val_second_best_item + eps;
            auto best_item = boost::get<Item>(&graph[bidder->best_item]);
            if (bid > best_item->high_bid) {
                best_item->high_bid = bid;
                best_item->high_bidder = bidder->id;
            }

        }


        // 3 Assign

        for (auto uncasted_item : iterator_item) {
            Item* item = boost::get<Item>(&graph[uncasted_item]);
            if (item->high_bid == -1) continue;

            item->cost += item->high_bid;

            if (gp.item2bidder[item->id] != -1) {
                gp.bidder2item[gp.item2bidder[item->id]] = -1;
                unassigned_bidders++;
            }

            gp.item2bidder[item->id] = item->high_bidder;
            gp.bidder2item[gp.item2bidder[item->id]] = item->id;
            unassigned_bidders--;
        }
    
    }

    elapsed = now() - t_start;
}



Weight perform_au(Graph& graph, duration& elapsed) {
    int n = int(boost::num_vertices(graph) / 2);
    Weight total_cost_auction = 0;

    auction_algorithm(graph, n, elapsed);

    std::cout << "\nThe matching is: ";
    for (int bidder = 0; bidder < n; ++bidder) {
        std::cout << "(" << bidder << "," << graph[boost::graph_bundle].bidder2item[bidder] << ")";
        int item = graph[boost::graph_bundle].bidder2item[bidder];
        total_cost_auction += boost::get(boost::edge_weight_t(), graph, (boost::edge(bidder, item + n, graph)).first);
    }
    std::cout << "\n";
    return total_cost_auction;
}

我将此与向量实现进行了比较,并注意到后者比我的要快得多(但是它们返回的总成本相同)。 是因为 boost::get 的复杂性吗? 如果有,为什么这么重?

我在 Ubuntu 机器上使用 g++ 编译器并编译应用程序,我在控制台中运行以下行:

g++ -std=c++2a -o ../bin/app BipartiteGraph.cpp MaximumWeightedMatching.cpp Auction.cpp AuctionArray.cpp Main.cpp

我分享了我的github 存储库的链接,以便您查看整个项目。

PS:如果您对加速算法有任何建议,那就太好了!

为什么重。

再次

FMap map_bidders = FMap(graph, any_interconnect, bidders);
FMap map_items = FMap(graph, any_interconnect, items);    

只是“希望”事物成为财产 map 并没有使它们如此。

此外,您的过滤谓词:

EdgeFilter any_interconnect = boost::keep_all{};
VertexFilter bidders = [graph](V v) -> bool { return boost::get<Bidder>(&(graph)[v]); };
VertexFilter items = [graph](V v) -> bool { return boost::get<Item>(&(graph)[v]); };

FMap map_bidders = FMap(graph, any_interconnect, bidders);
FMap map_items = FMap(graph, any_interconnect, items);    

他们...

  • 复制整个图(,),两次
  • 无用地get<>一个变体元素,只是为了丢弃它并返回bool

稍微好一些:

VertexFilter bidders = [&graph](V v) -> bool {
    return graph[v].which() == 0;
};
VertexFilter items = [&graph](V v) -> bool {
    return graph[v].which() == 1;
};

FMap map_bidders = FMap(graph, {}, bidders);
FMap map_items = FMap(graph, {}, items);    

但这一切都没什么用。 我并不惊讶这些东西需要时间,因为您知道您的图表是结构化的(N 个投标人)(N 个项目),所以

auto iterator_bidder = boost::make_iterator_range(vertices(map_bidders));
auto iterator_item = boost::make_iterator_range(vertices(map_items));

应该 只是:

auto [b,e] = vertices(graph);
auto iterator_bidder = boost::make_iterator_range(b, b + n);
auto iterator_item   = boost::make_iterator_range(b + n, e);

甚至那些都是矫枉过正的,因为你的顶点描述符无论如何都是不可或缺的:

auto const bidders = boost::irange(0, n);
auto const items   = boost::irange(n, 2 * n);

稍后我会阅读更多内容(家庭时间优先),因为我已经注意到了更多内容(例如,为什么将listS用作边缘容器选择器?)。

完成后会在这里发布。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM