COIN-OR::LEMON - Graph Library

Changeset 1024:b84e68af8248 in lemon-main


Ignore:
Timestamp:
11/25/10 22:45:29 (14 years ago)
Author:
Balazs Dezso <deba@…>
Branch:
default
Phase:
public
Message:

LGF reader and writer for bipartite graphs (#69)

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/lgf.dox

    r950 r1024  
    6464\endcode
    6565
    66 The \c \@arcs section is very similar to the \c \@nodes section, it
    67 again starts with a header line describing the names of the maps, but
    68 the \c "label" map is not obligatory here. The following lines
    69 describe the arcs. The first two tokens of each line are the source
    70 and the target node of the arc, respectively, then come the map
     66The \e LGF files can also contain bipartite graphs, in this case a
     67\c @red_nodes and a \c @blue_nodes sections describe the node set of the
     68graph. If a map is in both of these sections, then it can be used as a
     69regular node map.
     70
     71\code
     72 @red_nodes
     73 label  only_red_map   name
     74 1      "cherry"       "John"
     75 2      "Santa Claus"  "Jack"
     76 3      "blood"        "Jason"
     77 @blue_nodes
     78 label  name
     79 4      "Elisabeth"
     80 5      "Eve"
     81\endcode
     82
     83The \c \@arcs section is very similar to the \c \@nodes section,
     84it again starts with a header line describing the names of the maps,
     85but the \c "label" map is not obligatory here. The following lines
     86describe the arcs. The first two tokens of each line are
     87the source and the target node of the arc, respectively, then come the map
    7188values. The source and target tokens must be node labels.
    7289
  • lemon/full_graph.h

    r1020 r1024  
    992992    }
    993993
     994    using Parent::redNode;
     995    using Parent::blueNode;
     996
    994997    /// \brief Returns the red node with the given index.
    995998    ///
  • lemon/lgf_reader.h

    r966 r1024  
    21292129  }
    21302130
     2131  template <typename BGR>
     2132  class BpGraphReader;
     2133
     2134  template <typename TBGR>
     2135  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is = std::cin);
     2136  template <typename TBGR>
     2137  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const std::string& fn);
     2138  template <typename TBGR>
     2139  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char *fn);
     2140
     2141  /// \ingroup lemon_io
     2142  ///
     2143  /// \brief \ref lgf-format "LGF" reader for bipartite graphs
     2144  ///
     2145  /// This utility reads an \ref lgf-format "LGF" file.
     2146  ///
     2147  /// It can be used almost the same way as \c GraphReader, but it
     2148  /// reads the red and blue nodes from separate sections, and these
     2149  /// sections can contain different set of maps.
     2150  ///
     2151  /// The red and blue maps are read from the corresponding
     2152  /// sections. If a map is defined with the same name in both of
     2153  /// these sections, then it can be read as a node map.
     2154  template <typename BGR>
     2155  class BpGraphReader {
     2156  public:
     2157
     2158    typedef BGR Graph;
     2159
     2160  private:
     2161
     2162    TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
     2163
     2164    std::istream* _is;
     2165    bool local_is;
     2166    std::string _filename;
     2167
     2168    BGR& _graph;
     2169
     2170    std::string _nodes_caption;
     2171    std::string _edges_caption;
     2172    std::string _attributes_caption;
     2173
     2174    typedef std::map<std::string, Node> NodeIndex;
     2175    NodeIndex _node_index;
     2176    typedef std::map<std::string, Edge> EdgeIndex;
     2177    EdgeIndex _edge_index;
     2178
     2179    typedef std::vector<std::pair<std::string,
     2180      _reader_bits::MapStorageBase<Node>*> > NodeMaps;
     2181    NodeMaps _red_maps;
     2182    NodeMaps _blue_maps;
     2183
     2184    typedef std::vector<std::pair<std::string,
     2185      _reader_bits::MapStorageBase<Edge>*> > EdgeMaps;
     2186    EdgeMaps _edge_maps;
     2187
     2188    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
     2189      Attributes;
     2190    Attributes _attributes;
     2191
     2192    bool _use_nodes;
     2193    bool _use_edges;
     2194
     2195    bool _skip_nodes;
     2196    bool _skip_edges;
     2197
     2198    int line_num;
     2199    std::istringstream line;
     2200
     2201  public:
     2202
     2203    /// \brief Constructor
     2204    ///
     2205    /// Construct an undirected graph reader, which reads from the given
     2206    /// input stream.
     2207    BpGraphReader(BGR& graph, std::istream& is = std::cin)
     2208      : _is(&is), local_is(false), _graph(graph),
     2209        _use_nodes(false), _use_edges(false),
     2210        _skip_nodes(false), _skip_edges(false) {}
     2211
     2212    /// \brief Constructor
     2213    ///
     2214    /// Construct an undirected graph reader, which reads from the given
     2215    /// file.
     2216    BpGraphReader(BGR& graph, const std::string& fn)
     2217      : _is(new std::ifstream(fn.c_str())), local_is(true),
     2218        _filename(fn), _graph(graph),
     2219        _use_nodes(false), _use_edges(false),
     2220        _skip_nodes(false), _skip_edges(false) {
     2221      if (!(*_is)) {
     2222        delete _is;
     2223        throw IoError("Cannot open file", fn);
     2224      }
     2225    }
     2226
     2227    /// \brief Constructor
     2228    ///
     2229    /// Construct an undirected graph reader, which reads from the given
     2230    /// file.
     2231    BpGraphReader(BGR& graph, const char* fn)
     2232      : _is(new std::ifstream(fn)), local_is(true),
     2233        _filename(fn), _graph(graph),
     2234        _use_nodes(false), _use_edges(false),
     2235        _skip_nodes(false), _skip_edges(false) {
     2236      if (!(*_is)) {
     2237        delete _is;
     2238        throw IoError("Cannot open file", fn);
     2239      }
     2240    }
     2241
     2242    /// \brief Destructor
     2243    ~BpGraphReader() {
     2244      for (typename NodeMaps::iterator it = _red_maps.begin();
     2245           it != _red_maps.end(); ++it) {
     2246        delete it->second;
     2247      }
     2248
     2249      for (typename NodeMaps::iterator it = _blue_maps.begin();
     2250           it != _blue_maps.end(); ++it) {
     2251        delete it->second;
     2252      }
     2253
     2254      for (typename EdgeMaps::iterator it = _edge_maps.begin();
     2255           it != _edge_maps.end(); ++it) {
     2256        delete it->second;
     2257      }
     2258
     2259      for (typename Attributes::iterator it = _attributes.begin();
     2260           it != _attributes.end(); ++it) {
     2261        delete it->second;
     2262      }
     2263
     2264      if (local_is) {
     2265        delete _is;
     2266      }
     2267
     2268    }
     2269
     2270  private:
     2271    template <typename TBGR>
     2272    friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is);
     2273    template <typename TBGR>
     2274    friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph,
     2275                                             const std::string& fn);
     2276    template <typename TBGR>
     2277    friend BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char *fn);
     2278
     2279    BpGraphReader(BpGraphReader& other)
     2280      : _is(other._is), local_is(other.local_is), _graph(other._graph),
     2281        _use_nodes(other._use_nodes), _use_edges(other._use_edges),
     2282        _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
     2283
     2284      other._is = 0;
     2285      other.local_is = false;
     2286
     2287      _node_index.swap(other._node_index);
     2288      _edge_index.swap(other._edge_index);
     2289
     2290      _red_maps.swap(other._red_maps);
     2291      _blue_maps.swap(other._blue_maps);
     2292      _edge_maps.swap(other._edge_maps);
     2293      _attributes.swap(other._attributes);
     2294
     2295      _nodes_caption = other._nodes_caption;
     2296      _edges_caption = other._edges_caption;
     2297      _attributes_caption = other._attributes_caption;
     2298
     2299    }
     2300
     2301    BpGraphReader& operator=(const BpGraphReader&);
     2302
     2303  public:
     2304
     2305    /// \name Reading Rules
     2306    /// @{
     2307
     2308    /// \brief Node map reading rule
     2309    ///
     2310    /// Add a node map reading rule to the reader.
     2311    template <typename Map>
     2312    BpGraphReader& nodeMap(const std::string& caption, Map& map) {
     2313      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2314      _reader_bits::MapStorageBase<Node>* red_storage =
     2315        new _reader_bits::MapStorage<Node, Map>(map);
     2316      _red_maps.push_back(std::make_pair(caption, red_storage));
     2317      _reader_bits::MapStorageBase<Node>* blue_storage =
     2318        new _reader_bits::MapStorage<Node, Map>(map);
     2319      _blue_maps.push_back(std::make_pair(caption, blue_storage));
     2320      return *this;
     2321    }
     2322
     2323    /// \brief Node map reading rule
     2324    ///
     2325    /// Add a node map reading rule with specialized converter to the
     2326    /// reader.
     2327    template <typename Map, typename Converter>
     2328    BpGraphReader& nodeMap(const std::string& caption, Map& map,
     2329                           const Converter& converter = Converter()) {
     2330      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2331      _reader_bits::MapStorageBase<Node>* red_storage =
     2332        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
     2333      _red_maps.push_back(std::make_pair(caption, red_storage));
     2334      _reader_bits::MapStorageBase<Node>* blue_storage =
     2335        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
     2336      _blue_maps.push_back(std::make_pair(caption, blue_storage));
     2337      return *this;
     2338    }
     2339
     2340    /// Add a red map reading rule to the reader.
     2341    template <typename Map>
     2342    BpGraphReader& redMap(const std::string& caption, Map& map) {
     2343      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2344      _reader_bits::MapStorageBase<Node>* storage =
     2345        new _reader_bits::MapStorage<Node, Map>(map);
     2346      _red_maps.push_back(std::make_pair(caption, storage));
     2347      return *this;
     2348    }
     2349
     2350    /// \brief Red map reading rule
     2351    ///
     2352    /// Add a red map reading rule with specialized converter to the
     2353    /// reader.
     2354    template <typename Map, typename Converter>
     2355    BpGraphReader& redMap(const std::string& caption, Map& map,
     2356                          const Converter& converter = Converter()) {
     2357      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2358      _reader_bits::MapStorageBase<Node>* storage =
     2359        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
     2360      _red_maps.push_back(std::make_pair(caption, storage));
     2361      return *this;
     2362    }
     2363
     2364    /// Add a blue map reading rule to the reader.
     2365    template <typename Map>
     2366    BpGraphReader& blueMap(const std::string& caption, Map& map) {
     2367      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2368      _reader_bits::MapStorageBase<Node>* storage =
     2369        new _reader_bits::MapStorage<Node, Map>(map);
     2370      _blue_maps.push_back(std::make_pair(caption, storage));
     2371      return *this;
     2372    }
     2373
     2374    /// \brief Blue map reading rule
     2375    ///
     2376    /// Add a blue map reading rule with specialized converter to the
     2377    /// reader.
     2378    template <typename Map, typename Converter>
     2379    BpGraphReader& blueMap(const std::string& caption, Map& map,
     2380                           const Converter& converter = Converter()) {
     2381      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
     2382      _reader_bits::MapStorageBase<Node>* storage =
     2383        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
     2384      _blue_maps.push_back(std::make_pair(caption, storage));
     2385      return *this;
     2386    }
     2387
     2388    /// \brief Edge map reading rule
     2389    ///
     2390    /// Add an edge map reading rule to the reader.
     2391    template <typename Map>
     2392    BpGraphReader& edgeMap(const std::string& caption, Map& map) {
     2393      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
     2394      _reader_bits::MapStorageBase<Edge>* storage =
     2395        new _reader_bits::MapStorage<Edge, Map>(map);
     2396      _edge_maps.push_back(std::make_pair(caption, storage));
     2397      return *this;
     2398    }
     2399
     2400    /// \brief Edge map reading rule
     2401    ///
     2402    /// Add an edge map reading rule with specialized converter to the
     2403    /// reader.
     2404    template <typename Map, typename Converter>
     2405    BpGraphReader& edgeMap(const std::string& caption, Map& map,
     2406                          const Converter& converter = Converter()) {
     2407      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
     2408      _reader_bits::MapStorageBase<Edge>* storage =
     2409        new _reader_bits::MapStorage<Edge, Map, Converter>(map, converter);
     2410      _edge_maps.push_back(std::make_pair(caption, storage));
     2411      return *this;
     2412    }
     2413
     2414    /// \brief Arc map reading rule
     2415    ///
     2416    /// Add an arc map reading rule to the reader.
     2417    template <typename Map>
     2418    BpGraphReader& arcMap(const std::string& caption, Map& map) {
     2419      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
     2420      _reader_bits::MapStorageBase<Edge>* forward_storage =
     2421        new _reader_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
     2422      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
     2423      _reader_bits::MapStorageBase<Edge>* backward_storage =
     2424        new _reader_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
     2425      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
     2426      return *this;
     2427    }
     2428
     2429    /// \brief Arc map reading rule
     2430    ///
     2431    /// Add an arc map reading rule with specialized converter to the
     2432    /// reader.
     2433    template <typename Map, typename Converter>
     2434    BpGraphReader& arcMap(const std::string& caption, Map& map,
     2435                          const Converter& converter = Converter()) {
     2436      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
     2437      _reader_bits::MapStorageBase<Edge>* forward_storage =
     2438        new _reader_bits::GraphArcMapStorage<BGR, true, Map, Converter>
     2439        (_graph, map, converter);
     2440      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
     2441      _reader_bits::MapStorageBase<Edge>* backward_storage =
     2442        new _reader_bits::GraphArcMapStorage<BGR, false, Map, Converter>
     2443        (_graph, map, converter);
     2444      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
     2445      return *this;
     2446    }
     2447
     2448    /// \brief Attribute reading rule
     2449    ///
     2450    /// Add an attribute reading rule to the reader.
     2451    template <typename Value>
     2452    BpGraphReader& attribute(const std::string& caption, Value& value) {
     2453      _reader_bits::ValueStorageBase* storage =
     2454        new _reader_bits::ValueStorage<Value>(value);
     2455      _attributes.insert(std::make_pair(caption, storage));
     2456      return *this;
     2457    }
     2458
     2459    /// \brief Attribute reading rule
     2460    ///
     2461    /// Add an attribute reading rule with specialized converter to the
     2462    /// reader.
     2463    template <typename Value, typename Converter>
     2464    BpGraphReader& attribute(const std::string& caption, Value& value,
     2465                             const Converter& converter = Converter()) {
     2466      _reader_bits::ValueStorageBase* storage =
     2467        new _reader_bits::ValueStorage<Value, Converter>(value, converter);
     2468      _attributes.insert(std::make_pair(caption, storage));
     2469      return *this;
     2470    }
     2471
     2472    /// \brief Node reading rule
     2473    ///
     2474    /// Add a node reading rule to reader.
     2475    BpGraphReader& node(const std::string& caption, Node& node) {
     2476      typedef _reader_bits::MapLookUpConverter<Node> Converter;
     2477      Converter converter(_node_index);
     2478      _reader_bits::ValueStorageBase* storage =
     2479        new _reader_bits::ValueStorage<Node, Converter>(node, converter);
     2480      _attributes.insert(std::make_pair(caption, storage));
     2481      return *this;
     2482    }
     2483
     2484    /// \brief Edge reading rule
     2485    ///
     2486    /// Add an edge reading rule to reader.
     2487    BpGraphReader& edge(const std::string& caption, Edge& edge) {
     2488      typedef _reader_bits::MapLookUpConverter<Edge> Converter;
     2489      Converter converter(_edge_index);
     2490      _reader_bits::ValueStorageBase* storage =
     2491        new _reader_bits::ValueStorage<Edge, Converter>(edge, converter);
     2492      _attributes.insert(std::make_pair(caption, storage));
     2493      return *this;
     2494    }
     2495
     2496    /// \brief Arc reading rule
     2497    ///
     2498    /// Add an arc reading rule to reader.
     2499    BpGraphReader& arc(const std::string& caption, Arc& arc) {
     2500      typedef _reader_bits::GraphArcLookUpConverter<BGR> Converter;
     2501      Converter converter(_graph, _edge_index);
     2502      _reader_bits::ValueStorageBase* storage =
     2503        new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
     2504      _attributes.insert(std::make_pair(caption, storage));
     2505      return *this;
     2506    }
     2507
     2508    /// @}
     2509
     2510    /// \name Select Section by Name
     2511    /// @{
     2512
     2513    /// \brief Set \c \@nodes section to be read
     2514    ///
     2515    /// Set \c \@nodes section to be read.
     2516    BpGraphReader& nodes(const std::string& caption) {
     2517      _nodes_caption = caption;
     2518      return *this;
     2519    }
     2520
     2521    /// \brief Set \c \@edges section to be read
     2522    ///
     2523    /// Set \c \@edges section to be read.
     2524    BpGraphReader& edges(const std::string& caption) {
     2525      _edges_caption = caption;
     2526      return *this;
     2527    }
     2528
     2529    /// \brief Set \c \@attributes section to be read
     2530    ///
     2531    /// Set \c \@attributes section to be read.
     2532    BpGraphReader& attributes(const std::string& caption) {
     2533      _attributes_caption = caption;
     2534      return *this;
     2535    }
     2536
     2537    /// @}
     2538
     2539    /// \name Using Previously Constructed Node or Edge Set
     2540    /// @{
     2541
     2542    /// \brief Use previously constructed node set
     2543    ///
     2544    /// Use previously constructed node set, and specify the node
     2545    /// label map.
     2546    template <typename Map>
     2547    BpGraphReader& useNodes(const Map& map) {
     2548      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     2549      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
     2550      _use_nodes = true;
     2551      _writer_bits::DefaultConverter<typename Map::Value> converter;
     2552      for (NodeIt n(_graph); n != INVALID; ++n) {
     2553        _node_index.insert(std::make_pair(converter(map[n]), n));
     2554      }
     2555      return *this;
     2556    }
     2557
     2558    /// \brief Use previously constructed node set
     2559    ///
     2560    /// Use previously constructed node set, and specify the node
     2561    /// label map and a functor which converts the label map values to
     2562    /// \c std::string.
     2563    template <typename Map, typename Converter>
     2564    BpGraphReader& useNodes(const Map& map,
     2565                            const Converter& converter = Converter()) {
     2566      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     2567      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
     2568      _use_nodes = true;
     2569      for (NodeIt n(_graph); n != INVALID; ++n) {
     2570        _node_index.insert(std::make_pair(converter(map[n]), n));
     2571      }
     2572      return *this;
     2573    }
     2574
     2575    /// \brief Use previously constructed edge set
     2576    ///
     2577    /// Use previously constructed edge set, and specify the edge
     2578    /// label map.
     2579    template <typename Map>
     2580    BpGraphReader& useEdges(const Map& map) {
     2581      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
     2582      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
     2583      _use_edges = true;
     2584      _writer_bits::DefaultConverter<typename Map::Value> converter;
     2585      for (EdgeIt a(_graph); a != INVALID; ++a) {
     2586        _edge_index.insert(std::make_pair(converter(map[a]), a));
     2587      }
     2588      return *this;
     2589    }
     2590
     2591    /// \brief Use previously constructed edge set
     2592    ///
     2593    /// Use previously constructed edge set, and specify the edge
     2594    /// label map and a functor which converts the label map values to
     2595    /// \c std::string.
     2596    template <typename Map, typename Converter>
     2597    BpGraphReader& useEdges(const Map& map,
     2598                            const Converter& converter = Converter()) {
     2599      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
     2600      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
     2601      _use_edges = true;
     2602      for (EdgeIt a(_graph); a != INVALID; ++a) {
     2603        _edge_index.insert(std::make_pair(converter(map[a]), a));
     2604      }
     2605      return *this;
     2606    }
     2607
     2608    /// \brief Skip the reading of node section
     2609    ///
     2610    /// Omit the reading of the node section. This implies that each node
     2611    /// map reading rule will be abandoned, and the nodes of the graph
     2612    /// will not be constructed, which usually cause that the edge set
     2613    /// could not be read due to lack of node name
     2614    /// could not be read due to lack of node name resolving.
     2615    /// Therefore \c skipEdges() function should also be used, or
     2616    /// \c useNodes() should be used to specify the label of the nodes.
     2617    BpGraphReader& skipNodes() {
     2618      LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
     2619      _skip_nodes = true;
     2620      return *this;
     2621    }
     2622
     2623    /// \brief Skip the reading of edge section
     2624    ///
     2625    /// Omit the reading of the edge section. This implies that each edge
     2626    /// map reading rule will be abandoned, and the edges of the graph
     2627    /// will not be constructed.
     2628    BpGraphReader& skipEdges() {
     2629      LEMON_ASSERT(!_skip_edges, "Skip edges already set");
     2630      _skip_edges = true;
     2631      return *this;
     2632    }
     2633
     2634    /// @}
     2635
     2636  private:
     2637
     2638    bool readLine() {
     2639      std::string str;
     2640      while(++line_num, std::getline(*_is, str)) {
     2641        line.clear(); line.str(str);
     2642        char c;
     2643        if (line >> std::ws >> c && c != '#') {
     2644          line.putback(c);
     2645          return true;
     2646        }
     2647      }
     2648      return false;
     2649    }
     2650
     2651    bool readSuccess() {
     2652      return static_cast<bool>(*_is);
     2653    }
     2654
     2655    void skipSection() {
     2656      char c;
     2657      while (readSuccess() && line >> c && c != '@') {
     2658        readLine();
     2659      }
     2660      if (readSuccess()) {
     2661        line.putback(c);
     2662      }
     2663    }
     2664
     2665    void readRedNodes() {
     2666
     2667      std::vector<int> map_index(_red_maps.size());
     2668      int map_num, label_index;
     2669
     2670      char c;
     2671      if (!readLine() || !(line >> c) || c == '@') {
     2672        if (readSuccess() && line) line.putback(c);
     2673        if (!_red_maps.empty())
     2674          throw FormatError("Cannot find map names");
     2675        return;
     2676      }
     2677      line.putback(c);
     2678
     2679      {
     2680        std::map<std::string, int> maps;
     2681
     2682        std::string map;
     2683        int index = 0;
     2684        while (_reader_bits::readToken(line, map)) {
     2685          if (maps.find(map) != maps.end()) {
     2686            std::ostringstream msg;
     2687            msg << "Multiple occurence of red map: " << map;
     2688            throw FormatError(msg.str());
     2689          }
     2690          maps.insert(std::make_pair(map, index));
     2691          ++index;
     2692        }
     2693
     2694        for (int i = 0; i < static_cast<int>(_red_maps.size()); ++i) {
     2695          std::map<std::string, int>::iterator jt =
     2696            maps.find(_red_maps[i].first);
     2697          if (jt == maps.end()) {
     2698            std::ostringstream msg;
     2699            msg << "Map not found: " << _red_maps[i].first;
     2700            throw FormatError(msg.str());
     2701          }
     2702          map_index[i] = jt->second;
     2703        }
     2704
     2705        {
     2706          std::map<std::string, int>::iterator jt = maps.find("label");
     2707          if (jt != maps.end()) {
     2708            label_index = jt->second;
     2709          } else {
     2710            label_index = -1;
     2711          }
     2712        }
     2713        map_num = maps.size();
     2714      }
     2715
     2716      while (readLine() && line >> c && c != '@') {
     2717        line.putback(c);
     2718
     2719        std::vector<std::string> tokens(map_num);
     2720        for (int i = 0; i < map_num; ++i) {
     2721          if (!_reader_bits::readToken(line, tokens[i])) {
     2722            std::ostringstream msg;
     2723            msg << "Column not found (" << i + 1 << ")";
     2724            throw FormatError(msg.str());
     2725          }
     2726        }
     2727        if (line >> std::ws >> c)
     2728          throw FormatError("Extra character at the end of line");
     2729
     2730        Node n;
     2731        if (!_use_nodes) {
     2732          n = _graph.addRedNode();
     2733          if (label_index != -1)
     2734            _node_index.insert(std::make_pair(tokens[label_index], n));
     2735        } else {
     2736          if (label_index == -1)
     2737            throw FormatError("Label map not found");
     2738          typename std::map<std::string, Node>::iterator it =
     2739            _node_index.find(tokens[label_index]);
     2740          if (it == _node_index.end()) {
     2741            std::ostringstream msg;
     2742            msg << "Node with label not found: " << tokens[label_index];
     2743            throw FormatError(msg.str());
     2744          }
     2745          n = it->second;
     2746        }
     2747
     2748        for (int i = 0; i < static_cast<int>(_red_maps.size()); ++i) {
     2749          _red_maps[i].second->set(n, tokens[map_index[i]]);
     2750        }
     2751
     2752      }
     2753      if (readSuccess()) {
     2754        line.putback(c);
     2755      }
     2756    }
     2757
     2758    void readBlueNodes() {
     2759
     2760      std::vector<int> map_index(_blue_maps.size());
     2761      int map_num, label_index;
     2762
     2763      char c;
     2764      if (!readLine() || !(line >> c) || c == '@') {
     2765        if (readSuccess() && line) line.putback(c);
     2766        if (!_blue_maps.empty())
     2767          throw FormatError("Cannot find map names");
     2768        return;
     2769      }
     2770      line.putback(c);
     2771
     2772      {
     2773        std::map<std::string, int> maps;
     2774
     2775        std::string map;
     2776        int index = 0;
     2777        while (_reader_bits::readToken(line, map)) {
     2778          if (maps.find(map) != maps.end()) {
     2779            std::ostringstream msg;
     2780            msg << "Multiple occurence of blue map: " << map;
     2781            throw FormatError(msg.str());
     2782          }
     2783          maps.insert(std::make_pair(map, index));
     2784          ++index;
     2785        }
     2786
     2787        for (int i = 0; i < static_cast<int>(_blue_maps.size()); ++i) {
     2788          std::map<std::string, int>::iterator jt =
     2789            maps.find(_blue_maps[i].first);
     2790          if (jt == maps.end()) {
     2791            std::ostringstream msg;
     2792            msg << "Map not found: " << _blue_maps[i].first;
     2793            throw FormatError(msg.str());
     2794          }
     2795          map_index[i] = jt->second;
     2796        }
     2797
     2798        {
     2799          std::map<std::string, int>::iterator jt = maps.find("label");
     2800          if (jt != maps.end()) {
     2801            label_index = jt->second;
     2802          } else {
     2803            label_index = -1;
     2804          }
     2805        }
     2806        map_num = maps.size();
     2807      }
     2808
     2809      while (readLine() && line >> c && c != '@') {
     2810        line.putback(c);
     2811
     2812        std::vector<std::string> tokens(map_num);
     2813        for (int i = 0; i < map_num; ++i) {
     2814          if (!_reader_bits::readToken(line, tokens[i])) {
     2815            std::ostringstream msg;
     2816            msg << "Column not found (" << i + 1 << ")";
     2817            throw FormatError(msg.str());
     2818          }
     2819        }
     2820        if (line >> std::ws >> c)
     2821          throw FormatError("Extra character at the end of line");
     2822
     2823        Node n;
     2824        if (!_use_nodes) {
     2825          n = _graph.addBlueNode();
     2826          if (label_index != -1)
     2827            _node_index.insert(std::make_pair(tokens[label_index], n));
     2828        } else {
     2829          if (label_index == -1)
     2830            throw FormatError("Label map not found");
     2831          typename std::map<std::string, Node>::iterator it =
     2832            _node_index.find(tokens[label_index]);
     2833          if (it == _node_index.end()) {
     2834            std::ostringstream msg;
     2835            msg << "Node with label not found: " << tokens[label_index];
     2836            throw FormatError(msg.str());
     2837          }
     2838          n = it->second;
     2839        }
     2840
     2841        for (int i = 0; i < static_cast<int>(_blue_maps.size()); ++i) {
     2842          _blue_maps[i].second->set(n, tokens[map_index[i]]);
     2843        }
     2844
     2845      }
     2846      if (readSuccess()) {
     2847        line.putback(c);
     2848      }
     2849    }
     2850
     2851    void readEdges() {
     2852
     2853      std::vector<int> map_index(_edge_maps.size());
     2854      int map_num, label_index;
     2855
     2856      char c;
     2857      if (!readLine() || !(line >> c) || c == '@') {
     2858        if (readSuccess() && line) line.putback(c);
     2859        if (!_edge_maps.empty())
     2860          throw FormatError("Cannot find map names");
     2861        return;
     2862      }
     2863      line.putback(c);
     2864
     2865      {
     2866        std::map<std::string, int> maps;
     2867
     2868        std::string map;
     2869        int index = 0;
     2870        while (_reader_bits::readToken(line, map)) {
     2871          if (maps.find(map) != maps.end()) {
     2872            std::ostringstream msg;
     2873            msg << "Multiple occurence of edge map: " << map;
     2874            throw FormatError(msg.str());
     2875          }
     2876          maps.insert(std::make_pair(map, index));
     2877          ++index;
     2878        }
     2879
     2880        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
     2881          std::map<std::string, int>::iterator jt =
     2882            maps.find(_edge_maps[i].first);
     2883          if (jt == maps.end()) {
     2884            std::ostringstream msg;
     2885            msg << "Map not found: " << _edge_maps[i].first;
     2886            throw FormatError(msg.str());
     2887          }
     2888          map_index[i] = jt->second;
     2889        }
     2890
     2891        {
     2892          std::map<std::string, int>::iterator jt = maps.find("label");
     2893          if (jt != maps.end()) {
     2894            label_index = jt->second;
     2895          } else {
     2896            label_index = -1;
     2897          }
     2898        }
     2899        map_num = maps.size();
     2900      }
     2901
     2902      while (readLine() && line >> c && c != '@') {
     2903        line.putback(c);
     2904
     2905        std::string source_token;
     2906        std::string target_token;
     2907
     2908        if (!_reader_bits::readToken(line, source_token))
     2909          throw FormatError("Red node not found");
     2910
     2911        if (!_reader_bits::readToken(line, target_token))
     2912          throw FormatError("Blue node not found");
     2913
     2914        std::vector<std::string> tokens(map_num);
     2915        for (int i = 0; i < map_num; ++i) {
     2916          if (!_reader_bits::readToken(line, tokens[i])) {
     2917            std::ostringstream msg;
     2918            msg << "Column not found (" << i + 1 << ")";
     2919            throw FormatError(msg.str());
     2920          }
     2921        }
     2922        if (line >> std::ws >> c)
     2923          throw FormatError("Extra character at the end of line");
     2924
     2925        Edge e;
     2926        if (!_use_edges) {
     2927
     2928          typename NodeIndex::iterator it;
     2929
     2930          it = _node_index.find(source_token);
     2931          if (it == _node_index.end()) {
     2932            std::ostringstream msg;
     2933            msg << "Item not found: " << source_token;
     2934            throw FormatError(msg.str());
     2935          }
     2936          Node source = it->second;
     2937          if (!_graph.red(source)) {
     2938            std::ostringstream msg;
     2939            msg << "Item is not red node: " << source_token;
     2940            throw FormatError(msg.str());
     2941          }
     2942
     2943          it = _node_index.find(target_token);
     2944          if (it == _node_index.end()) {
     2945            std::ostringstream msg;
     2946            msg << "Item not found: " << target_token;
     2947            throw FormatError(msg.str());
     2948          }
     2949          Node target = it->second;
     2950          if (!_graph.blue(target)) {
     2951            std::ostringstream msg;
     2952            msg << "Item is not red node: " << source_token;
     2953            throw FormatError(msg.str());
     2954          }
     2955
     2956          e = _graph.addEdge(source, target);
     2957          if (label_index != -1)
     2958            _edge_index.insert(std::make_pair(tokens[label_index], e));
     2959        } else {
     2960          if (label_index == -1)
     2961            throw FormatError("Label map not found");
     2962          typename std::map<std::string, Edge>::iterator it =
     2963            _edge_index.find(tokens[label_index]);
     2964          if (it == _edge_index.end()) {
     2965            std::ostringstream msg;
     2966            msg << "Edge with label not found: " << tokens[label_index];
     2967            throw FormatError(msg.str());
     2968          }
     2969          e = it->second;
     2970        }
     2971
     2972        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
     2973          _edge_maps[i].second->set(e, tokens[map_index[i]]);
     2974        }
     2975
     2976      }
     2977      if (readSuccess()) {
     2978        line.putback(c);
     2979      }
     2980    }
     2981
     2982    void readAttributes() {
     2983
     2984      std::set<std::string> read_attr;
     2985
     2986      char c;
     2987      while (readLine() && line >> c && c != '@') {
     2988        line.putback(c);
     2989
     2990        std::string attr, token;
     2991        if (!_reader_bits::readToken(line, attr))
     2992          throw FormatError("Attribute name not found");
     2993        if (!_reader_bits::readToken(line, token))
     2994          throw FormatError("Attribute value not found");
     2995        if (line >> c)
     2996          throw FormatError("Extra character at the end of line");
     2997
     2998        {
     2999          std::set<std::string>::iterator it = read_attr.find(attr);
     3000          if (it != read_attr.end()) {
     3001            std::ostringstream msg;
     3002            msg << "Multiple occurence of attribute: " << attr;
     3003            throw FormatError(msg.str());
     3004          }
     3005          read_attr.insert(attr);
     3006        }
     3007
     3008        {
     3009          typename Attributes::iterator it = _attributes.lower_bound(attr);
     3010          while (it != _attributes.end() && it->first == attr) {
     3011            it->second->set(token);
     3012            ++it;
     3013          }
     3014        }
     3015
     3016      }
     3017      if (readSuccess()) {
     3018        line.putback(c);
     3019      }
     3020      for (typename Attributes::iterator it = _attributes.begin();
     3021           it != _attributes.end(); ++it) {
     3022        if (read_attr.find(it->first) == read_attr.end()) {
     3023          std::ostringstream msg;
     3024          msg << "Attribute not found: " << it->first;
     3025          throw FormatError(msg.str());
     3026        }
     3027      }
     3028    }
     3029
     3030  public:
     3031
     3032    /// \name Execution of the Reader
     3033    /// @{
     3034
     3035    /// \brief Start the batch processing
     3036    ///
     3037    /// This function starts the batch processing
     3038    void run() {
     3039
     3040      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
     3041
     3042      bool red_nodes_done = _skip_nodes;
     3043      bool blue_nodes_done = _skip_nodes;
     3044      bool edges_done = _skip_edges;
     3045      bool attributes_done = false;
     3046
     3047      line_num = 0;
     3048      readLine();
     3049      skipSection();
     3050
     3051      while (readSuccess()) {
     3052        try {
     3053          char c;
     3054          std::string section, caption;
     3055          line >> c;
     3056          _reader_bits::readToken(line, section);
     3057          _reader_bits::readToken(line, caption);
     3058
     3059          if (line >> c)
     3060            throw FormatError("Extra character at the end of line");
     3061
     3062          if (section == "red_nodes" && !red_nodes_done) {
     3063            if (_nodes_caption.empty() || _nodes_caption == caption) {
     3064              readRedNodes();
     3065              red_nodes_done = true;
     3066            }
     3067          } else if (section == "blue_nodes" && !blue_nodes_done) {
     3068            if (_nodes_caption.empty() || _nodes_caption == caption) {
     3069              readBlueNodes();
     3070              blue_nodes_done = true;
     3071            }
     3072          } else if ((section == "edges" || section == "arcs") &&
     3073                     !edges_done) {
     3074            if (_edges_caption.empty() || _edges_caption == caption) {
     3075              readEdges();
     3076              edges_done = true;
     3077            }
     3078          } else if (section == "attributes" && !attributes_done) {
     3079            if (_attributes_caption.empty() || _attributes_caption == caption) {
     3080              readAttributes();
     3081              attributes_done = true;
     3082            }
     3083          } else {
     3084            readLine();
     3085            skipSection();
     3086          }
     3087        } catch (FormatError& error) {
     3088          error.line(line_num);
     3089          error.file(_filename);
     3090          throw;
     3091        }
     3092      }
     3093
     3094      if (!red_nodes_done) {
     3095        throw FormatError("Section @red_nodes not found");
     3096      }
     3097
     3098      if (!blue_nodes_done) {
     3099        throw FormatError("Section @blue_nodes not found");
     3100      }
     3101
     3102      if (!edges_done) {
     3103        throw FormatError("Section @edges not found");
     3104      }
     3105
     3106      if (!attributes_done && !_attributes.empty()) {
     3107        throw FormatError("Section @attributes not found");
     3108      }
     3109
     3110    }
     3111
     3112    /// @}
     3113
     3114  };
     3115
     3116  /// \ingroup lemon_io
     3117  ///
     3118  /// \brief Return a \ref BpGraphReader class
     3119  ///
     3120  /// This function just returns a \ref BpGraphReader class.
     3121  ///
     3122  /// With this function a graph can be read from an
     3123  /// \ref lgf-format "LGF" file or input stream with several maps and
     3124  /// attributes. For example, there is bipartite weighted matching problem
     3125  /// on a graph, i.e. a graph with a \e weight map on the edges. This
     3126  /// graph can be read with the following code:
     3127  ///
     3128  ///\code
     3129  ///ListBpGraph graph;
     3130  ///ListBpGraph::EdgeMap<int> weight(graph);
     3131  ///bpGraphReader(graph, std::cin).
     3132  ///  edgeMap("weight", weight).
     3133  ///  run();
     3134  ///\endcode
     3135  ///
     3136  /// For a complete documentation, please see the \ref BpGraphReader
     3137  /// class documentation.
     3138  /// \warning Don't forget to put the \ref BpGraphReader::run() "run()"
     3139  /// to the end of the parameter list.
     3140  /// \relates BpGraphReader
     3141  /// \sa bpGraphReader(TBGR& graph, const std::string& fn)
     3142  /// \sa bpGraphReader(TBGR& graph, const char* fn)
     3143  template <typename TBGR>
     3144  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, std::istream& is) {
     3145    BpGraphReader<TBGR> tmp(graph, is);
     3146    return tmp;
     3147  }
     3148
     3149  /// \brief Return a \ref BpGraphReader class
     3150  ///
     3151  /// This function just returns a \ref BpGraphReader class.
     3152  /// \relates BpGraphReader
     3153  /// \sa bpGraphReader(TBGR& graph, std::istream& is)
     3154  template <typename TBGR>
     3155  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const std::string& fn) {
     3156    BpGraphReader<TBGR> tmp(graph, fn);
     3157    return tmp;
     3158  }
     3159
     3160  /// \brief Return a \ref BpGraphReader class
     3161  ///
     3162  /// This function just returns a \ref BpGraphReader class.
     3163  /// \relates BpGraphReader
     3164  /// \sa bpGraphReader(TBGR& graph, std::istream& is)
     3165  template <typename TBGR>
     3166  BpGraphReader<TBGR> bpGraphReader(TBGR& graph, const char* fn) {
     3167    BpGraphReader<TBGR> tmp(graph, fn);
     3168    return tmp;
     3169  }
     3170
    21313171  class SectionReader;
    21323172
  • lemon/lgf_writer.h

    r877 r1024  
    987987  /// \ingroup lemon_io
    988988  ///
    989   /// \brief \ref lgf-format "LGF" writer for directed graphs
     989  /// \brief \ref lgf-format "LGF" writer for undirected graphs
    990990  ///
    991991  /// This utility writes an \ref lgf-format "LGF" file.
     
    10431043    /// \brief Constructor
    10441044    ///
    1045     /// Construct a directed graph writer, which writes to the given
    1046     /// output stream.
     1045    /// Construct an undirected graph writer, which writes to the
     1046    /// given output stream.
    10471047    GraphWriter(const GR& graph, std::ostream& os = std::cout)
    10481048      : _os(&os), local_os(false), _graph(graph),
     
    10511051    /// \brief Constructor
    10521052    ///
    1053     /// Construct a directed graph writer, which writes to the given
     1053    /// Construct a undirected graph writer, which writes to the given
    10541054    /// output file.
    10551055    GraphWriter(const GR& graph, const std::string& fn)
     
    10641064    /// \brief Constructor
    10651065    ///
    1066     /// Construct a directed graph writer, which writes to the given
     1066    /// Construct a undirected graph writer, which writes to the given
    10671067    /// output file.
    10681068    GraphWriter(const GR& graph, const char* fn)
     
    12901290    }
    12911291
    1292     /// \brief Add an additional caption to the \c \@arcs section
    1293     ///
    1294     /// Add an additional caption to the \c \@arcs section.
     1292    /// \brief Add an additional caption to the \c \@edges section
     1293    ///
     1294    /// Add an additional caption to the \c \@edges section.
    12951295    GraphWriter& edges(const std::string& caption) {
    12961296      _edges_caption = caption;
     
    16061606  GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn) {
    16071607    GraphWriter<TGR> tmp(graph, fn);
     1608    return tmp;
     1609  }
     1610
     1611  template <typename BGR>
     1612  class BpGraphWriter;
     1613
     1614  template <typename TBGR>
     1615  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
     1616                                    std::ostream& os = std::cout);
     1617  template <typename TBGR>
     1618  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn);
     1619  template <typename TBGR>
     1620  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn);
     1621
     1622  /// \ingroup lemon_io
     1623  ///
     1624  /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs
     1625  ///
     1626  /// This utility writes an \ref lgf-format "LGF" file.
     1627  ///
     1628  /// It can be used almost the same way as \c GraphWriter, but it
     1629  /// reads the red and blue nodes from separate sections, and these
     1630  /// sections can contain different set of maps.
     1631  ///
     1632  /// The red and blue maps are written to the corresponding
     1633  /// sections. The node maps are written to both of these sections
     1634  /// with the same map name.
     1635  template <typename BGR>
     1636  class BpGraphWriter {
     1637  public:
     1638
     1639    typedef BGR BpGraph;
     1640    TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
     1641
     1642  private:
     1643
     1644
     1645    std::ostream* _os;
     1646    bool local_os;
     1647
     1648    const BGR& _graph;
     1649
     1650    std::string _nodes_caption;
     1651    std::string _edges_caption;
     1652    std::string _attributes_caption;
     1653
     1654    typedef std::map<Node, std::string> NodeIndex;
     1655    NodeIndex _node_index;
     1656    typedef std::map<Edge, std::string> EdgeIndex;
     1657    EdgeIndex _edge_index;
     1658
     1659    typedef std::vector<std::pair<std::string,
     1660      _writer_bits::MapStorageBase<Node>* > > NodeMaps;
     1661    NodeMaps _red_maps;
     1662    NodeMaps _blue_maps;
     1663
     1664    typedef std::vector<std::pair<std::string,
     1665      _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
     1666    EdgeMaps _edge_maps;
     1667
     1668    typedef std::vector<std::pair<std::string,
     1669      _writer_bits::ValueStorageBase*> > Attributes;
     1670    Attributes _attributes;
     1671
     1672    bool _skip_nodes;
     1673    bool _skip_edges;
     1674
     1675  public:
     1676
     1677    /// \brief Constructor
     1678    ///
     1679    /// Construct a bipartite graph writer, which writes to the given
     1680    /// output stream.
     1681    BpGraphWriter(const BGR& graph, std::ostream& os = std::cout)
     1682      : _os(&os), local_os(false), _graph(graph),
     1683        _skip_nodes(false), _skip_edges(false) {}
     1684
     1685    /// \brief Constructor
     1686    ///
     1687    /// Construct a bipartite graph writer, which writes to the given
     1688    /// output file.
     1689    BpGraphWriter(const BGR& graph, const std::string& fn)
     1690      : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
     1691        _skip_nodes(false), _skip_edges(false) {
     1692      if (!(*_os)) {
     1693        delete _os;
     1694        throw IoError("Cannot write file", fn);
     1695      }
     1696    }
     1697
     1698    /// \brief Constructor
     1699    ///
     1700    /// Construct a bipartite graph writer, which writes to the given
     1701    /// output file.
     1702    BpGraphWriter(const BGR& graph, const char* fn)
     1703      : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
     1704        _skip_nodes(false), _skip_edges(false) {
     1705      if (!(*_os)) {
     1706        delete _os;
     1707        throw IoError("Cannot write file", fn);
     1708      }
     1709    }
     1710
     1711    /// \brief Destructor
     1712    ~BpGraphWriter() {
     1713      for (typename NodeMaps::iterator it = _red_maps.begin();
     1714           it != _red_maps.end(); ++it) {
     1715        delete it->second;
     1716      }
     1717
     1718      for (typename NodeMaps::iterator it = _blue_maps.begin();
     1719           it != _blue_maps.end(); ++it) {
     1720        delete it->second;
     1721      }
     1722
     1723      for (typename EdgeMaps::iterator it = _edge_maps.begin();
     1724           it != _edge_maps.end(); ++it) {
     1725        delete it->second;
     1726      }
     1727
     1728      for (typename Attributes::iterator it = _attributes.begin();
     1729           it != _attributes.end(); ++it) {
     1730        delete it->second;
     1731      }
     1732
     1733      if (local_os) {
     1734        delete _os;
     1735      }
     1736    }
     1737
     1738  private:
     1739
     1740    template <typename TBGR>
     1741    friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
     1742                                             std::ostream& os);
     1743    template <typename TBGR>
     1744    friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
     1745                                             const std::string& fn);
     1746    template <typename TBGR>
     1747    friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char *fn);
     1748
     1749    BpGraphWriter(BpGraphWriter& other)
     1750      : _os(other._os), local_os(other.local_os), _graph(other._graph),
     1751        _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
     1752
     1753      other._os = 0;
     1754      other.local_os = false;
     1755
     1756      _node_index.swap(other._node_index);
     1757      _edge_index.swap(other._edge_index);
     1758
     1759      _red_maps.swap(other._red_maps);
     1760      _blue_maps.swap(other._blue_maps);
     1761      _edge_maps.swap(other._edge_maps);
     1762      _attributes.swap(other._attributes);
     1763
     1764      _nodes_caption = other._nodes_caption;
     1765      _edges_caption = other._edges_caption;
     1766      _attributes_caption = other._attributes_caption;
     1767    }
     1768
     1769    BpGraphWriter& operator=(const BpGraphWriter&);
     1770
     1771  public:
     1772
     1773    /// \name Writing Rules
     1774    /// @{
     1775
     1776    /// \brief Node map writing rule
     1777    ///
     1778    /// Add a node map writing rule to the writer.
     1779    template <typename Map>
     1780    BpGraphWriter& nodeMap(const std::string& caption, const Map& map) {
     1781      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1782      _writer_bits::MapStorageBase<Node>* red_storage =
     1783        new _writer_bits::MapStorage<Node, Map>(map);
     1784      _red_maps.push_back(std::make_pair(caption, red_storage));
     1785      _writer_bits::MapStorageBase<Node>* blue_storage =
     1786        new _writer_bits::MapStorage<Node, Map>(map);
     1787      _blue_maps.push_back(std::make_pair(caption, blue_storage));
     1788      return *this;
     1789    }
     1790
     1791    /// \brief Node map writing rule
     1792    ///
     1793    /// Add a node map writing rule with specialized converter to the
     1794    /// writer.
     1795    template <typename Map, typename Converter>
     1796    BpGraphWriter& nodeMap(const std::string& caption, const Map& map,
     1797                           const Converter& converter = Converter()) {
     1798      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1799      _writer_bits::MapStorageBase<Node>* red_storage =
     1800        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
     1801      _red_maps.push_back(std::make_pair(caption, red_storage));
     1802      _writer_bits::MapStorageBase<Node>* blue_storage =
     1803        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
     1804      _blue_maps.push_back(std::make_pair(caption, blue_storage));
     1805      return *this;
     1806    }
     1807
     1808    /// \brief Red map writing rule
     1809    ///
     1810    /// Add a red map writing rule to the writer.
     1811    template <typename Map>
     1812    BpGraphWriter& redMap(const std::string& caption, const Map& map) {
     1813      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1814      _writer_bits::MapStorageBase<Node>* storage =
     1815        new _writer_bits::MapStorage<Node, Map>(map);
     1816      _red_maps.push_back(std::make_pair(caption, storage));
     1817      return *this;
     1818    }
     1819
     1820    /// \brief Red map writing rule
     1821    ///
     1822    /// Add a red map writing rule with specialized converter to the
     1823    /// writer.
     1824    template <typename Map, typename Converter>
     1825    BpGraphWriter& redMap(const std::string& caption, const Map& map,
     1826                          const Converter& converter = Converter()) {
     1827      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1828      _writer_bits::MapStorageBase<Node>* storage =
     1829        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
     1830      _red_maps.push_back(std::make_pair(caption, storage));
     1831      return *this;
     1832    }
     1833
     1834    /// \brief Blue map writing rule
     1835    ///
     1836    /// Add a blue map writing rule to the writer.
     1837    template <typename Map>
     1838    BpGraphWriter& blueMap(const std::string& caption, const Map& map) {
     1839      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1840      _writer_bits::MapStorageBase<Node>* storage =
     1841        new _writer_bits::MapStorage<Node, Map>(map);
     1842      _blue_maps.push_back(std::make_pair(caption, storage));
     1843      return *this;
     1844    }
     1845
     1846    /// \brief Blue map writing rule
     1847    ///
     1848    /// Add a blue map writing rule with specialized converter to the
     1849    /// writer.
     1850    template <typename Map, typename Converter>
     1851    BpGraphWriter& blueMap(const std::string& caption, const Map& map,
     1852                           const Converter& converter = Converter()) {
     1853      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
     1854      _writer_bits::MapStorageBase<Node>* storage =
     1855        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
     1856      _blue_maps.push_back(std::make_pair(caption, storage));
     1857      return *this;
     1858    }
     1859
     1860    /// \brief Edge map writing rule
     1861    ///
     1862    /// Add an edge map writing rule to the writer.
     1863    template <typename Map>
     1864    BpGraphWriter& edgeMap(const std::string& caption, const Map& map) {
     1865      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
     1866      _writer_bits::MapStorageBase<Edge>* storage =
     1867        new _writer_bits::MapStorage<Edge, Map>(map);
     1868      _edge_maps.push_back(std::make_pair(caption, storage));
     1869      return *this;
     1870    }
     1871
     1872    /// \brief Edge map writing rule
     1873    ///
     1874    /// Add an edge map writing rule with specialized converter to the
     1875    /// writer.
     1876    template <typename Map, typename Converter>
     1877    BpGraphWriter& edgeMap(const std::string& caption, const Map& map,
     1878                          const Converter& converter = Converter()) {
     1879      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
     1880      _writer_bits::MapStorageBase<Edge>* storage =
     1881        new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
     1882      _edge_maps.push_back(std::make_pair(caption, storage));
     1883      return *this;
     1884    }
     1885
     1886    /// \brief Arc map writing rule
     1887    ///
     1888    /// Add an arc map writing rule to the writer.
     1889    template <typename Map>
     1890    BpGraphWriter& arcMap(const std::string& caption, const Map& map) {
     1891      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
     1892      _writer_bits::MapStorageBase<Edge>* forward_storage =
     1893        new _writer_bits::GraphArcMapStorage<BGR, true, Map>(_graph, map);
     1894      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
     1895      _writer_bits::MapStorageBase<Edge>* backward_storage =
     1896        new _writer_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
     1897      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
     1898      return *this;
     1899    }
     1900
     1901    /// \brief Arc map writing rule
     1902    ///
     1903    /// Add an arc map writing rule with specialized converter to the
     1904    /// writer.
     1905    template <typename Map, typename Converter>
     1906    BpGraphWriter& arcMap(const std::string& caption, const Map& map,
     1907                          const Converter& converter = Converter()) {
     1908      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
     1909      _writer_bits::MapStorageBase<Edge>* forward_storage =
     1910        new _writer_bits::GraphArcMapStorage<BGR, true, Map, Converter>
     1911        (_graph, map, converter);
     1912      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
     1913      _writer_bits::MapStorageBase<Edge>* backward_storage =
     1914        new _writer_bits::GraphArcMapStorage<BGR, false, Map, Converter>
     1915        (_graph, map, converter);
     1916      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
     1917      return *this;
     1918    }
     1919
     1920    /// \brief Attribute writing rule
     1921    ///
     1922    /// Add an attribute writing rule to the writer.
     1923    template <typename Value>
     1924    BpGraphWriter& attribute(const std::string& caption, const Value& value) {
     1925      _writer_bits::ValueStorageBase* storage =
     1926        new _writer_bits::ValueStorage<Value>(value);
     1927      _attributes.push_back(std::make_pair(caption, storage));
     1928      return *this;
     1929    }
     1930
     1931    /// \brief Attribute writing rule
     1932    ///
     1933    /// Add an attribute writing rule with specialized converter to the
     1934    /// writer.
     1935    template <typename Value, typename Converter>
     1936    BpGraphWriter& attribute(const std::string& caption, const Value& value,
     1937                             const Converter& converter = Converter()) {
     1938      _writer_bits::ValueStorageBase* storage =
     1939        new _writer_bits::ValueStorage<Value, Converter>(value, converter);
     1940      _attributes.push_back(std::make_pair(caption, storage));
     1941      return *this;
     1942    }
     1943
     1944    /// \brief Node writing rule
     1945    ///
     1946    /// Add a node writing rule to the writer.
     1947    BpGraphWriter& node(const std::string& caption, const Node& node) {
     1948      typedef _writer_bits::MapLookUpConverter<Node> Converter;
     1949      Converter converter(_node_index);
     1950      _writer_bits::ValueStorageBase* storage =
     1951        new _writer_bits::ValueStorage<Node, Converter>(node, converter);
     1952      _attributes.push_back(std::make_pair(caption, storage));
     1953      return *this;
     1954    }
     1955
     1956    /// \brief Edge writing rule
     1957    ///
     1958    /// Add an edge writing rule to writer.
     1959    BpGraphWriter& edge(const std::string& caption, const Edge& edge) {
     1960      typedef _writer_bits::MapLookUpConverter<Edge> Converter;
     1961      Converter converter(_edge_index);
     1962      _writer_bits::ValueStorageBase* storage =
     1963        new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
     1964      _attributes.push_back(std::make_pair(caption, storage));
     1965      return *this;
     1966    }
     1967
     1968    /// \brief Arc writing rule
     1969    ///
     1970    /// Add an arc writing rule to writer.
     1971    BpGraphWriter& arc(const std::string& caption, const Arc& arc) {
     1972      typedef _writer_bits::GraphArcLookUpConverter<BGR> Converter;
     1973      Converter converter(_graph, _edge_index);
     1974      _writer_bits::ValueStorageBase* storage =
     1975        new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
     1976      _attributes.push_back(std::make_pair(caption, storage));
     1977      return *this;
     1978    }
     1979
     1980    /// \name Section Captions
     1981    /// @{
     1982
     1983    /// \brief Add an additional caption to the \c \@red_nodes and
     1984    /// \c \@blue_nodes section
     1985    ///
     1986    /// Add an additional caption to the \c \@red_nodes and \c
     1987    /// \@blue_nodes section.
     1988    BpGraphWriter& nodes(const std::string& caption) {
     1989      _nodes_caption = caption;
     1990      return *this;
     1991    }
     1992
     1993    /// \brief Add an additional caption to the \c \@edges section
     1994    ///
     1995    /// Add an additional caption to the \c \@edges section.
     1996    BpGraphWriter& edges(const std::string& caption) {
     1997      _edges_caption = caption;
     1998      return *this;
     1999    }
     2000
     2001    /// \brief Add an additional caption to the \c \@attributes section
     2002    ///
     2003    /// Add an additional caption to the \c \@attributes section.
     2004    BpGraphWriter& attributes(const std::string& caption) {
     2005      _attributes_caption = caption;
     2006      return *this;
     2007    }
     2008
     2009    /// \name Skipping Section
     2010    /// @{
     2011
     2012    /// \brief Skip writing the node set
     2013    ///
     2014    /// The \c \@red_nodes and \c \@blue_nodes section will not be
     2015    /// written to the stream.
     2016    BpGraphWriter& skipNodes() {
     2017      LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
     2018      _skip_nodes = true;
     2019      return *this;
     2020    }
     2021
     2022    /// \brief Skip writing edge set
     2023    ///
     2024    /// The \c \@edges section will not be written to the stream.
     2025    BpGraphWriter& skipEdges() {
     2026      LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
     2027      _skip_edges = true;
     2028      return *this;
     2029    }
     2030
     2031    /// @}
     2032
     2033  private:
     2034
     2035    void writeRedNodes() {
     2036      _writer_bits::MapStorageBase<Node>* label = 0;
     2037      for (typename NodeMaps::iterator it = _red_maps.begin();
     2038           it != _red_maps.end(); ++it) {
     2039        if (it->first == "label") {
     2040          label = it->second;
     2041          break;
     2042        }
     2043      }
     2044
     2045      *_os << "@red_nodes";
     2046      if (!_nodes_caption.empty()) {
     2047        _writer_bits::writeToken(*_os << ' ', _nodes_caption);
     2048      }
     2049      *_os << std::endl;
     2050
     2051      if (label == 0) {
     2052        *_os << "label" << '\t';
     2053      }
     2054      for (typename NodeMaps::iterator it = _red_maps.begin();
     2055           it != _red_maps.end(); ++it) {
     2056        _writer_bits::writeToken(*_os, it->first) << '\t';
     2057      }
     2058      *_os << std::endl;
     2059
     2060      std::vector<Node> nodes;
     2061      for (RedIt n(_graph); n != INVALID; ++n) {
     2062        nodes.push_back(n);
     2063      }
     2064
     2065      if (label == 0) {
     2066        IdMap<BGR, Node> id_map(_graph);
     2067        _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
     2068        std::sort(nodes.begin(), nodes.end(), id_less);
     2069      } else {
     2070        label->sort(nodes);
     2071      }
     2072
     2073      for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
     2074        Node n = nodes[i];
     2075        if (label == 0) {
     2076          std::ostringstream os;
     2077          os << _graph.id(n);
     2078          _writer_bits::writeToken(*_os, os.str());
     2079          *_os << '\t';
     2080          _node_index.insert(std::make_pair(n, os.str()));
     2081        }
     2082        for (typename NodeMaps::iterator it = _red_maps.begin();
     2083             it != _red_maps.end(); ++it) {
     2084          std::string value = it->second->get(n);
     2085          _writer_bits::writeToken(*_os, value);
     2086          if (it->first == "label") {
     2087            _node_index.insert(std::make_pair(n, value));
     2088          }
     2089          *_os << '\t';
     2090        }
     2091        *_os << std::endl;
     2092      }
     2093    }
     2094
     2095    void writeBlueNodes() {
     2096      _writer_bits::MapStorageBase<Node>* label = 0;
     2097      for (typename NodeMaps::iterator it = _blue_maps.begin();
     2098           it != _blue_maps.end(); ++it) {
     2099        if (it->first == "label") {
     2100          label = it->second;
     2101          break;
     2102        }
     2103      }
     2104
     2105      *_os << "@blue_nodes";
     2106      if (!_nodes_caption.empty()) {
     2107        _writer_bits::writeToken(*_os << ' ', _nodes_caption);
     2108      }
     2109      *_os << std::endl;
     2110
     2111      if (label == 0) {
     2112        *_os << "label" << '\t';
     2113      }
     2114      for (typename NodeMaps::iterator it = _blue_maps.begin();
     2115           it != _blue_maps.end(); ++it) {
     2116        _writer_bits::writeToken(*_os, it->first) << '\t';
     2117      }
     2118      *_os << std::endl;
     2119
     2120      std::vector<Node> nodes;
     2121      for (BlueIt n(_graph); n != INVALID; ++n) {
     2122        nodes.push_back(n);
     2123      }
     2124
     2125      if (label == 0) {
     2126        IdMap<BGR, Node> id_map(_graph);
     2127        _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
     2128        std::sort(nodes.begin(), nodes.end(), id_less);
     2129      } else {
     2130        label->sort(nodes);
     2131      }
     2132
     2133      for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
     2134        Node n = nodes[i];
     2135        if (label == 0) {
     2136          std::ostringstream os;
     2137          os << _graph.id(n);
     2138          _writer_bits::writeToken(*_os, os.str());
     2139          *_os << '\t';
     2140          _node_index.insert(std::make_pair(n, os.str()));
     2141        }
     2142        for (typename NodeMaps::iterator it = _blue_maps.begin();
     2143             it != _blue_maps.end(); ++it) {
     2144          std::string value = it->second->get(n);
     2145          _writer_bits::writeToken(*_os, value);
     2146          if (it->first == "label") {
     2147            _node_index.insert(std::make_pair(n, value));
     2148          }
     2149          *_os << '\t';
     2150        }
     2151        *_os << std::endl;
     2152      }
     2153    }
     2154
     2155    void createRedNodeIndex() {
     2156      _writer_bits::MapStorageBase<Node>* label = 0;
     2157      for (typename NodeMaps::iterator it = _red_maps.begin();
     2158           it != _red_maps.end(); ++it) {
     2159        if (it->first == "label") {
     2160          label = it->second;
     2161          break;
     2162        }
     2163      }
     2164
     2165      if (label == 0) {
     2166        for (NodeIt n(_graph); n != INVALID; ++n) {
     2167          std::ostringstream os;
     2168          os << _graph.id(n);
     2169          _node_index.insert(std::make_pair(n, os.str()));
     2170        }
     2171      } else {
     2172        for (NodeIt n(_graph); n != INVALID; ++n) {
     2173          std::string value = label->get(n);
     2174          _node_index.insert(std::make_pair(n, value));
     2175        }
     2176      }
     2177    }
     2178
     2179    void createBlueNodeIndex() {
     2180      _writer_bits::MapStorageBase<Node>* label = 0;
     2181      for (typename NodeMaps::iterator it = _blue_maps.begin();
     2182           it != _blue_maps.end(); ++it) {
     2183        if (it->first == "label") {
     2184          label = it->second;
     2185          break;
     2186        }
     2187      }
     2188
     2189      if (label == 0) {
     2190        for (NodeIt n(_graph); n != INVALID; ++n) {
     2191          std::ostringstream os;
     2192          os << _graph.id(n);
     2193          _node_index.insert(std::make_pair(n, os.str()));
     2194        }
     2195      } else {
     2196        for (NodeIt n(_graph); n != INVALID; ++n) {
     2197          std::string value = label->get(n);
     2198          _node_index.insert(std::make_pair(n, value));
     2199        }
     2200      }
     2201    }
     2202
     2203    void writeEdges() {
     2204      _writer_bits::MapStorageBase<Edge>* label = 0;
     2205      for (typename EdgeMaps::iterator it = _edge_maps.begin();
     2206           it != _edge_maps.end(); ++it) {
     2207        if (it->first == "label") {
     2208          label = it->second;
     2209          break;
     2210        }
     2211      }
     2212
     2213      *_os << "@edges";
     2214      if (!_edges_caption.empty()) {
     2215        _writer_bits::writeToken(*_os << ' ', _edges_caption);
     2216      }
     2217      *_os << std::endl;
     2218
     2219      *_os << '\t' << '\t';
     2220      if (label == 0) {
     2221        *_os << "label" << '\t';
     2222      }
     2223      for (typename EdgeMaps::iterator it = _edge_maps.begin();
     2224           it != _edge_maps.end(); ++it) {
     2225        _writer_bits::writeToken(*_os, it->first) << '\t';
     2226      }
     2227      *_os << std::endl;
     2228
     2229      std::vector<Edge> edges;
     2230      for (EdgeIt n(_graph); n != INVALID; ++n) {
     2231        edges.push_back(n);
     2232      }
     2233
     2234      if (label == 0) {
     2235        IdMap<BGR, Edge> id_map(_graph);
     2236        _writer_bits::MapLess<IdMap<BGR, Edge> > id_less(id_map);
     2237        std::sort(edges.begin(), edges.end(), id_less);
     2238      } else {
     2239        label->sort(edges);
     2240      }
     2241
     2242      for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
     2243        Edge e = edges[i];
     2244        _writer_bits::writeToken(*_os, _node_index.
     2245                                 find(_graph.redNode(e))->second);
     2246        *_os << '\t';
     2247        _writer_bits::writeToken(*_os, _node_index.
     2248                                 find(_graph.blueNode(e))->second);
     2249        *_os << '\t';
     2250        if (label == 0) {
     2251          std::ostringstream os;
     2252          os << _graph.id(e);
     2253          _writer_bits::writeToken(*_os, os.str());
     2254          *_os << '\t';
     2255          _edge_index.insert(std::make_pair(e, os.str()));
     2256        }
     2257        for (typename EdgeMaps::iterator it = _edge_maps.begin();
     2258             it != _edge_maps.end(); ++it) {
     2259          std::string value = it->second->get(e);
     2260          _writer_bits::writeToken(*_os, value);
     2261          if (it->first == "label") {
     2262            _edge_index.insert(std::make_pair(e, value));
     2263          }
     2264          *_os << '\t';
     2265        }
     2266        *_os << std::endl;
     2267      }
     2268    }
     2269
     2270    void createEdgeIndex() {
     2271      _writer_bits::MapStorageBase<Edge>* label = 0;
     2272      for (typename EdgeMaps::iterator it = _edge_maps.begin();
     2273           it != _edge_maps.end(); ++it) {
     2274        if (it->first == "label") {
     2275          label = it->second;
     2276          break;
     2277        }
     2278      }
     2279
     2280      if (label == 0) {
     2281        for (EdgeIt e(_graph); e != INVALID; ++e) {
     2282          std::ostringstream os;
     2283          os << _graph.id(e);
     2284          _edge_index.insert(std::make_pair(e, os.str()));
     2285        }
     2286      } else {
     2287        for (EdgeIt e(_graph); e != INVALID; ++e) {
     2288          std::string value = label->get(e);
     2289          _edge_index.insert(std::make_pair(e, value));
     2290        }
     2291      }
     2292    }
     2293
     2294    void writeAttributes() {
     2295      if (_attributes.empty()) return;
     2296      *_os << "@attributes";
     2297      if (!_attributes_caption.empty()) {
     2298        _writer_bits::writeToken(*_os << ' ', _attributes_caption);
     2299      }
     2300      *_os << std::endl;
     2301      for (typename Attributes::iterator it = _attributes.begin();
     2302           it != _attributes.end(); ++it) {
     2303        _writer_bits::writeToken(*_os, it->first) << ' ';
     2304        _writer_bits::writeToken(*_os, it->second->get());
     2305        *_os << std::endl;
     2306      }
     2307    }
     2308
     2309  public:
     2310
     2311    /// \name Execution of the Writer
     2312    /// @{
     2313
     2314    /// \brief Start the batch processing
     2315    ///
     2316    /// This function starts the batch processing.
     2317    void run() {
     2318      if (!_skip_nodes) {
     2319        writeRedNodes();
     2320        writeBlueNodes();
     2321      } else {
     2322        createRedNodeIndex();
     2323        createBlueNodeIndex();
     2324      }
     2325      if (!_skip_edges) {
     2326        writeEdges();
     2327      } else {
     2328        createEdgeIndex();
     2329      }
     2330      writeAttributes();
     2331    }
     2332
     2333    /// \brief Give back the stream of the writer
     2334    ///
     2335    /// Give back the stream of the writer
     2336    std::ostream& ostream() {
     2337      return *_os;
     2338    }
     2339
     2340    /// @}
     2341  };
     2342
     2343  /// \ingroup lemon_io
     2344  ///
     2345  /// \brief Return a \ref BpGraphWriter class
     2346  ///
     2347  /// This function just returns a \ref BpGraphWriter class.
     2348  ///
     2349  /// With this function a bipartite graph can be write to a file or output
     2350  /// stream in \ref lgf-format "LGF" format with several maps and
     2351  /// attributes. For example, with the following code a bipartite
     2352  /// weighted matching problem can be written to the standard output,
     2353  /// i.e. a graph with a \e weight map on the edges:
     2354  ///
     2355  ///\code
     2356  ///ListBpGraph graph;
     2357  ///ListBpGraph::EdgeMap<int> weight(graph);
     2358  ///  // Setting the weight map
     2359  ///bpGraphWriter(graph, std::cout).
     2360  ///  edgeMap("weight", weight).
     2361  ///  run();
     2362  ///\endcode
     2363  ///
     2364  /// For a complete documentation, please see the \ref BpGraphWriter
     2365  /// class documentation.
     2366  /// \warning Don't forget to put the \ref BpGraphWriter::run() "run()"
     2367  /// to the end of the parameter list.
     2368  /// \relates BpGraphWriter
     2369  /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn)
     2370  /// \sa bpGraphWriter(const TBGR& graph, const char* fn)
     2371  template <typename TBGR>
     2372  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, std::ostream& os) {
     2373    BpGraphWriter<TBGR> tmp(graph, os);
     2374    return tmp;
     2375  }
     2376
     2377  /// \brief Return a \ref BpGraphWriter class
     2378  ///
     2379  /// This function just returns a \ref BpGraphWriter class.
     2380  /// \relates BpGraphWriter
     2381  /// \sa graphWriter(const TBGR& graph, std::ostream& os)
     2382  template <typename TBGR>
     2383  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn) {
     2384    BpGraphWriter<TBGR> tmp(graph, fn);
     2385    return tmp;
     2386  }
     2387
     2388  /// \brief Return a \ref BpGraphWriter class
     2389  ///
     2390  /// This function just returns a \ref BpGraphWriter class.
     2391  /// \relates BpGraphWriter
     2392  /// \sa graphWriter(const TBGR& graph, std::ostream& os)
     2393  template <typename TBGR>
     2394  BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn) {
     2395    BpGraphWriter<TBGR> tmp(graph, fn);
    16082396    return tmp;
    16092397  }
Note: See TracChangeset for help on using the changeset viewer.