Workshop on Generative Technologies 2010
LEMON – an Open Source C++ Graph Template Library 1
Bal´azs Dezs˝o2 Department of Algorithms and Their Applications E¨ otv¨ os Lor´ and University Budapest, Hungary
Alp´ar J¨ uttner2 Centre for Wireless Network Design University of Bedfordshire Luton, United Kingdom Department of Operations Research E¨ otv¨ os Lor´ and University Budapest, Hungary
P´eter Kov´acs2 Department of Algorithms and Their Applications E¨ otv¨ os Lor´ and University Budapest, Hungary
Abstract This paper introduces LEMON, a generic open source C++ library of graph and network algorithms and related data structures. It is a package of highly efficient and versatile tools with simple and convenient interface, targeting both computer scientists and the operations research community, as well as serving educational purposes. In this paper, the basic design concepts, features and performance of LEMON are compared to similar software packages, namely BGL (Boost Graph Library) and LEDA. Various implementation details are also discussed demonstrating the sophisticated use of C++ templates and other techniques. Due to its clear concepts and design, the ease of use and impressive performance, LEMON proved to be a remarkable alternative to similar open source or commercial libraries. Keywords: C++, library, graph, network, generic, template, algorithm
1
Introduction
LEMON [16] is a C++ template library with focus on combinatorial optimization tasks connected mainly with graphs and networks. Its name is an abbreviation of Library for Efficient Modeling and Optimization in Networks. LEMON is an open 1 2
The LEMON project is supported by EGRES [9]. E-mail:
[email protected],
[email protected],
[email protected]
˝ , Ju ¨ttner, and Kova ´cs Dezso
source software project of Egerv´ary Research Group on Combinatorial Optimization (EGRES) [9] at Department of Operations Research, E¨otv¨os Lor´and University, Budapest, Hungary. It is also a member of the COIN-OR initiative [6], a collection of open source projects related to operations research. Its clear design and the permissive licensing scheme make LEMON favorable for commercial and non-commercial software development, as well as research purposes. The goal of the library is to provide efficient, easy-to-use and well-cooperating software components, which help solving complex real-life optimization problems. These components include graph implementations and related data structures, fundamental graph and network algorithms (such as graph search, shortest path, spanning tree, matching and network flow algorithms) besides various auxiliary tools. Furthermore, the library provides a common high-level interface for several linear programming (LP) and mixed integer programming (MIP) [7] solvers. The basic motivation for developing LEMON was to support researchers and practitioners working in the area of graph theory and network optimization by establishing an open source library that is more suitable for them than other alternatives on the market. At present, LEMON is extensively used for research, including network design, traffic routing and general graph theory [1,4,13,20], as well as in education at E¨ otv¨ os Lor´ and University and Budapest University of Technology and Economics. It is also used in several commercial applications. The rest of this paper is organized as follows. Section 2 provides an overview of the main concepts and features of LEMON compared to BGL [2] and LEDA [15], the most widely known and highly regarded C++ graph libraries. Section 3 describes selected details of the implementation demonstrating the applied language techniques. In Section 4, the performance of the discussed libraries is compared through benchmark tests of fundamental algorithms. Finally, some general conclusions are drawn in Section 5.
2
Overview
Probably, the best known C++ graph library is BGL, that is why the readers are introduced to LEMON through simple and equivalent sample codes using these two libraries. In Figure 1, both codes construct a directed graph, assign lengths to the arcs and run Dijkstra’s algorithm. These examples also show that programs using LEMON tend to be shorter and easier to understand, since the user does not have to deal with various template techniques (like template metaprogram lists and traits classes). 2.1
Graph Structures
Although LEMON is a generic library, the main graph structures are not template classes, which is made possible by an important design decision. Namely, all data assigned to nodes and arcs are stored separately from the graph structures (see Section 2.3). The example in Figure 1 uses ListDigraph, which is a doubly-linked adjacency list based directed graph implementation. Another important digraph structure is 2
˝ , Ju ¨ttner, and Kova ´cs Dezso typedef adjacency_list graph_t; typedef graph_traits traits_t; graph_t g; property_map::type length = get(edge_weight, g);
ListDigraph g; ListDigraph::ArcMap length(g); ListDigraph::Node s = g.addNode(); ListDigraph::Node t = g.addNode(); // add more nodes ListDigraph::Arc a = g.addArc(s, t); length[a] = 8; // add more arcs
traits_t::vertex_descriptor s = add_vertex(g), t = add_vertex(g); // add more vertices
ListDigraph::NodeMap dist(g); dijkstra(g, length) .distMap(dist).run(s);
traits_t::edge_descriptor e = add_edge(s, t, g).first; length[e] = 8; // add more edges vector dist(num_vertices(g)); dijkstra_shortest_paths(g, s, distance_map(&dist[0]));
Fig. 1. Sample codes using BGL and LEMON, respectively
SmartDigraph, which stores the nodes and arcs continuously in vectors and uses simply-linked lists for keeping track of the incident arcs of each node. Therefore, it has smaller memory footprint and it can be considerably faster, at the cost that nodes and arcs cannot be removed from it. ListGraph and SmartGraph are the undirected versions of these classes. In addition to these general structures, LEMON also contains special purpose classes for handling full graphs, grid graphs and hypercube graphs. BGL implements a single adjacency list based graph class, but it can be customized with template parameters that specify the internal storage structures for nodes and arcs. BGL also contains a matrix based graph type, which is missing from LEMON, but the full graph structures with subgraph adaptors (see Section 2.5) provide reasonable substitutes for that. In LEMON, the undirected Graph concept also fulfills the Digraph concept, in such a way that each edge of a graph can also be regarded as two oppositely directed arcs. As a result, all directed graph algorithms automatically run on undirected graphs, as well (provided it makes sense). Furthermore, some algorithms can be implemented simpler (e.g., planar graph algorithms), because we can distinguish the undirected edges from their directed variants. This solution entirely differs from BGL, where directed and undirected graphs have the same interfaces, but with different semantics. Using undirected graphs in BGL, the edges are usually considered undirected, but they have directions in some cases (for example, in iterations), which could be confusing. Moreover, BGL does not allow to define a property map whose keys are the directed variants of the edges, although it would also be useful in algorithms. The LEDA graph implementation is closed source, but it is probably quite similar to the general graph structures of LEMON. The main difference is that digraphs and graphs are implemented in the same class in LEDA and there are member functions to switch between the two modes. 2.2
Iterators
LEMON iterators do not adhere to the STL compatibility, and so they provide a more convenient interface. They are initialized to the first item in the traversed 3
˝ , Ju ¨ttner, and Kova ´cs Dezso
range by their constructors and their validity is checked by comparing them to a global constant INVALID. In addition, iterators are convertible to the corresponding item types, without having to use operator*(). This is not confusing, since the program context always indicates whether we refer to the iterator or to the graph item (they do not have conflicting functionalities). Recall the examples shown in Figure 1. In LEMON, the computed distances of the nodes can be printed to the standard output like this. for (ListDigraph::NodeIt v(g); v != INVALID; ++v) { cout