Использовать библиотеку графов / сетевую библиотеку узлов или написать свою собственную?

Я пытаюсь решить, идти ли с предварительно созданной сетевой библиотекой графа/узла или свернуть свой собственный.

я реализую некоторые алгоритмы поиска графов, которые могут потребовать значительной настройки структуры классов узла и/или ребер.

причина, по которой я не уверен, что делать, заключается в том, что я не уверен, что настройка предварительно сделанного может быть дороже/проблема, чем сделать свой собственный в первую очередь. Мне также любопытно, но менее любопытно, о спектакле компромиссы.

есть ли у кого-нибудь прямой опыт использования одной из библиотек и есть советы, основанные на истории успеха или неудачи? Я хочу услышать худшее, чтобы, что бы я ни выбрал, я знал, во что ввязываюсь.

есть только два, которые я нашел в своем поиске до сих пор:библиотека графов Boost (BGL) и Леший. Конкретные советы по любому из них или предложения для других также высоко ценятся. BGL кажется чертовски загадочным. Стоит ли бороться?

9 ответов


возможно, я могу дать небольшое руководство по BGL.

библиотека очень гибкая. Стоимость этого заключается в том, что синтаксис может быть очень барочным, чтобы вместить все возможности. Однако он достаточно гибок, чтобы простые вещи можно было делать просто.

к сожалению, документация boost идет полным ходом, предоставляя описание только полной сложности, без намека на то, насколько простыми могут быть вещи.

( "любой достаточно развитая технология неотличима от магии" - Артур Кларк. Ему следовало бы сказать :" любая передовая технология, достаточно плохо документированная, неотличима от магии!"--4-->

считаем:

typedef property_map<Graph, vertex_index_t>::type IndexMap;
IndexMap index = get(vertex_index, g);
typedef graph_traits<Graph>::vertex_iterator vertex_iter;
std::pair<vertex_iter, vertex_iter> vp;
for (vp = vertices(g); vp.first != vp.second; ++vp.first) {
   std::cout << index[*vp.first] <<  " ";
}

вот как "быстрый тур" предлагает нам распечатать список вершин графа. Однако небольшое исследование показывает, что вершина - это не более чем целочисленный индекс, и код можно значительно упростить до

for (int v = *vertices(g).first; v != *vertices(g).second; ++v)
    std::cout << v << " ";

возможно есть некоторые волшебные вещи, которые не могут быть достигнуты с этим упрощенным кодом, но для каждого дня используйте его разумно резко обрезать синтаксис, который инкрустирует BGL, чтобы вы могли видеть, что вы кодируете.

иногда сложный синтаксис не может быть удален. (Или, возможно, я просто не заметил скрытой истины). Затем я обычно использую небольшую функцию утилиты для инкапсуляции сложности abd, чтобы держать ее подальше от алгоритма, над которым я работаю.

например, я часто нужно сделать петлю над дочерними элементами вершины

vector<int> getVertexChildren( int v )
{
    vector<int> vc;
    typedef std::pair<graph_traits<graph_t>::out_edge_iterator, graph_traits<graph_t>::out_edge_iterator> out_edge_iter_pair_t;
    for( out_edge_iter_pair_t ep = out_edges(v,m_tree);
        ep.first != ep.second; ++(ep.first))
    {
        vc.push_back( target( *ep.first, m_tree ) );
    }
    return vc;
}
#define FOR_ALL_CHILDREN( v ) vector<int> vc=getVertexChildren(v); BOOST_FOR_EACH( int child, vc )

суть в следующем: идите вперед и используйте BGL. Это можно упростить, чтобы делать простые вещи, но как только вы научитесь использовать его, вся огромная гибкость будет доступна, когда вам это нужно.


" требуется значительная настройка структуры класса узла и/или ребер."

вы смотрели на функцию "связанные свойства" BGL?

http://www.boost.org/doc/libs/1_40_0/libs/graph/doc/bundles.html

этот и не капельки acrcane.

вы определяете классы для своих ребер и вершин

class cMyVertex
{
…
};
class cMyEdge
{
…
};

Теперь вы определяете тип графика, который будет использовать ваш классы

typedef boost::adjacency_list<
    boost::listS, boost::vecS, boost::bidirectionalS,
    cMyVertex, cMyEdge > graph_t;

Теперь вы можете создавать графики этого типа, которые будут использовать свои занятия, какими бы они ни были, для вершин и ребер.

вы можете получить доступ к атрибутам и методам классов в очень естественным способом

Graph_t g(10)       // create a graph with 10 vertices
g[1].setA1( “alpha” );  // invoke an accessor on node #1

недавно я дал библиотеке графов boost пробную версию для задачи кратчайшего пути Dijkstras. Результаты:

  • высокая производительность

  • очень мало код

  • очень гибкий и расширяемый

  • трудно понять или отладить

Совет: использовать но прежде чем сделать это читать библиотека Boost Graph: руководство пользователя и Справочное Руководство


Я думаю, что если вы можете использовать алгоритмы обхода графика, стоит использовать график Boost. Создание и использование пользовательских вершин довольно просто. Примеры, включенные в BGL, были полезны для обучения его использованию.

Я согласен с Клиффордом, я использовал GraphViz, чтобы помочь визуализировать график во время разработки и нашел его очень полезным.


вы также можете попробовать с лимон библиотека графа.

Я мог бы использовать его для выполнения поиска кратчайшего пути Dijsktra после чтения графика из файла конфигурации.

только что вышла новая версия.


Я свернул свой собственный. Вы не должны следовать этому примеру, если вы абсолютно уверены, что вам нужно.

тем не менее, это отличный опыт обучения, если вы теория графов ржавая.

У меня было много "веселья" с объединением орграфов с использованием операторов EBNF и выполнением исключения epsilon и минимизации на основе Хопкрофта. Особенно с минимизацией, если вы можете позвонить отчаянно пытаясь найти хорошую информацию и выяснить, как это работает "весело": - (

Если вы делаете свой собственный, я рекомендую отделять операции высокого уровня от структур данных низкого уровня-разных классов, а не только разных методов. Я не - и довольно скоро я буду сильно рефакторинг, потому что это плохое решение.

некоторые графики аннотируют узлы, некоторые аннотируют ребра,некоторые оба. Иногда полезны две аннотации, даже если они являются внешними ключами для некоторых внешних данных. Например, в конечных машинах ребро может быть аннотировано с помощью ввода и выход. Вы, вероятно, будете заинтересованы в детерминизме WRT вход, но не выход, поэтому наличие их обоих скрыто за одним идентификатором - это боль, и это помимо всей проблемы вторичных контейнеров для поиска того, что делает этот идентификатор.

кроме того, иногда вы просто хотите работать с вещами, которые не были разработаны явно как орграф IYSWIM - например, куча узлов структуры данных, которые связаны друг с другом.

IOW, полезно иметь возможность подключаться различные представления орграфов, но все же используют одни и те же инструменты высокого уровня для многих операций.

IMO я получил это право, когда я написал класс "tree tool", который делает такие вещи, как итерация и подписка в порядке treeview и порядке тегов элементов XML. Базовое представление дерева является подключаемым (шаблон на основе политики). С орграфами я облажался.

в любом случае, я не знаю, что Boost или любая другая библиотека графиков на самом деле предоставляет, но если он предоставляет то, что вам нужно, я говорю использовать он. Это избавит от головной боли.


Это действительно не краткий ответ, его больше добавить к тому, что уже было сказано.

решение этой проблемы зависит от контекста проблемы. Если вы хотите получить большое представление о том, как работают алгоритмы графа и программное обеспечение. Написать свой. Если вы хотите получить расширенные знания алгоритмов и структур графов или реализовать их в своей собственной программе, изучите стандартную библиотеку графов. (См. причины использования многоразового использования код)

лучшее из обоих миров. Сделать оба. Если вы растянуты во времени, получите книгу об этом или следуйте учебникам и примерам.

еще одно предложение: задайте новый острый вопрос о том, что является {лучшей, самой надежной, самой простой в освоении} библиотекой графов для {опишите очень общую проблему}? Это поможет вам выбрать, чему учиться, а не пытаться наугад найти лучший, который соответствует вашим потребностям. Кто-то уже видел эту проблему, спросить совета.

Использование Многоразового Кода:

  1. код, который кто-то другой написал, включая тестовые случаи, как правило, будет более надежным, чем ваш собственный.
  2. исправления легче реализовать (с обновлениями компонента, который вы повторно используете), это верно в Boost (так как они делают частые обновления, и что Boost рецензируется).
  3. как только вы узнаете одну структуру, вы можете применить ее к другим приложениям... кто знает, может быть, вы получите работу позже в жизни, используя рамки. Компании предпочитают использовать колесо повторно, а не изобретать его заново.

прежде чем принять решение о создании собственной библиотеки графов, я бы хорошо посмотрел на igraph (http://igraph.sourceforge.net/). Он написан на C и чрезвычайно быстр и предлагает более широкий спектр базовых и продвинутых алгоритмов графов (включая визуализацию). Кроме того, он имеет оболочку python для быстрого кодирования, поэтому я думаю, что это решение сочетает скорость кодирования и скорость выполнения.


Я использую BGL очень много, но то, что беспокоит меня с BGL, - это отсутствие базовых алгоритмов, таких как edge и vertex connectivity, min cost flow и общее идеальное соответствие максимального веса, просто чтобы назвать те, которые я пропускаю больше всего.

LEMON предлагает все это, а также имеет более простой синтаксис, что меня беспокоит с LEMON-это проблемы установки и компиляции на платформах WINDOWS, но я, вероятно, переключусь на LEMON, несмотря на эти проблемы.