COIN-OR::LEMON - Graph Library

Ticket #380: 380-max-clique-b05e65c06f22.patch

File 380-max-clique-b05e65c06f22.patch, 25.1 KB (added by Peter Kovacs, 14 years ago)
  • doc/groups.dox

    # HG changeset patch
    # User Peter Kovacs <kpeter@inf.elte.hu>
    # Date 1279723824 -7200
    # Node ID b05e65c06f22166ae451323dc8baf213b9848be8
    # Parent  24b3f18ed9e2bea99ab482c493c3db769362ecf0
    Add a heuristic algorithm for the max clique problem (#380)
    
    It applies a recent iterated local search method that is quite simple
    but really efficient and robust.
    
    diff --git a/doc/groups.dox b/doc/groups.dox
    a b  
    551551*/
    552552
    553553/**
    554 @defgroup approx Approximation Algorithms
     554@defgroup approx_algs Approximation Algorithms
    555555@ingroup algs
    556556\brief Approximation algorithms.
    557557
  • doc/references.bib

    diff --git a/doc/references.bib b/doc/references.bib
    a b  
    297297  school =       {University College},
    298298  address =      {Dublin, Ireland},
    299299  year =         1991,
    300   month =        sep,
     300  month =        sep
    301301}
     302
     303%%%%% Other algorithms %%%%%
     304
     305@article{grosso08maxclique,
     306  author =       {Andrea Grosso and Marco Locatelli and Wayne Pullan},
     307  title =        {Simple ingredients leading to very efficient
     308                  heuristics for the maximum clique problem},
     309  journal =      {Journal of Heuristics},
     310  year =         2008,
     311  volume =       14,
     312  number =       6,
     313  pages =        {587--612}
     314}
  • lemon/Makefile.am

    diff --git a/lemon/Makefile.am b/lemon/Makefile.am
    a b  
    105105        lemon/maps.h \
    106106        lemon/matching.h \
    107107        lemon/math.h \
     108        lemon/max_clique.h \
    108109        lemon/min_cost_arborescence.h \
    109110        lemon/nauty_reader.h \
    110111        lemon/network_simplex.h \
  • new file lemon/max_clique.h

    diff --git a/lemon/max_clique.h b/lemon/max_clique.h
    new file mode 100644
    - +  
     1/* -*- mode: C++; indent-tabs-mode: nil; -*-
     2 *
     3 * This file is a part of LEMON, a generic C++ optimization library.
     4 *
     5 * Copyright (C) 2003-2010
     6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8 *
     9 * Permission to use, modify and distribute this software is granted
     10 * provided that this copyright notice appears in all copies. For
     11 * precise terms see the accompanying LICENSE file.
     12 *
     13 * This software is provided "AS IS" with no warranty of any kind,
     14 * express or implied, and with no claim as to its suitability for any
     15 * purpose.
     16 *
     17 */
     18
     19#ifndef LEMON_MAX_CLIQUE_H
     20#define LEMON_MAX_CLIQUE_H
     21
     22/// \ingroup approx_algs
     23///
     24/// \file
     25/// \brief An effficient heuristic algorithm for the maximum clique problem
     26
     27#include <vector>
     28#include <limits>
     29#include <lemon/core.h>
     30#include <lemon/random.h>
     31
     32namespace lemon {
     33
     34  /// \addtogroup approx_algs
     35  /// @{
     36
     37  /// \brief Implementation of an efficient heuristic algorithm
     38  /// for the maximum clique problem.
     39  ///
     40  /// \ref MaxClique implements the iterated local search algorithm of
     41  /// Grosso, Locatelli, and Pullan for solving the \e maximum \e clique
     42  /// \e problem \ref grosso08maxclique.
     43  /// It is to find the largest complete subgraph (\e clique) in an
     44  /// undirected graph, i.e., the largest set of nodes where each
     45  /// pair of nodes is connected.
     46  ///
     47  /// This class provides a simple but highly efficient and robust heuristic
     48  /// method that quickly finds a large clique, but not necessarily the
     49  /// largest one.
     50  ///
     51  /// \tparam GR The undirected graph type the algorithm runs on.
     52  ///
     53  /// \note %MaxClique provides three different node selection rules,
     54  /// from which the most powerful one is used by default.
     55  /// For more information, see \ref SelectionRule.
     56  template <typename GR>
     57  class MaxClique
     58  {
     59  public:
     60
     61    /// \brief Constants for specifying the node selection rule.
     62    ///
     63    /// Enum type containing constants for specifying the node selection rule
     64    /// for the \ref run() function.
     65    ///
     66    /// During the algorithm, nodes are selected for addition to the current
     67    /// clique according to the applied rule.
     68    /// In general, the PENALTY_BASED rule turned out to be the most powerful
     69    /// and the most robust, thus it is the default option.
     70    /// However, another selection rule can be specified using the \ref run()
     71    /// function with the proper parameter.
     72    enum SelectionRule {
     73
     74      /// A node is selected randomly without any evaluation at each step.
     75      RANDOM,
     76
     77      /// A node of maximum degree is selected randomly at each step.
     78      DEGREE_BASED,
     79
     80      /// A node of minimum penalty is selected randomly at each step.
     81      /// The node penalties are updated adaptively after each stage of the
     82      /// search process.
     83      PENALTY_BASED
     84    };
     85
     86  private:
     87
     88    TEMPLATE_GRAPH_TYPEDEFS(GR);
     89
     90    typedef std::vector<int> IntVector;
     91    typedef std::vector<char> BoolVector;
     92    typedef std::vector<BoolVector> BoolMatrix;
     93    // Note: vector<char> is used instead of vector<bool> for efficiency reasons
     94
     95    const GR &_graph;
     96    IntNodeMap _id;
     97   
     98    // Internal matrix representation of the graph
     99    BoolMatrix _gr;
     100    int _n;
     101 
     102    // The current clique
     103    BoolVector _clique;
     104    int _size;
     105
     106    // The best clique found so far
     107    BoolVector _best_clique;
     108    int _best_size;
     109
     110    // The "distances" of the nodes from the current clique.
     111    // _delta[u] is the number of nodes in the clique that are
     112    // not connected with u.
     113    IntVector _delta;
     114
     115    // The current tabu set
     116    BoolVector _tabu;
     117   
     118    // Random number generator
     119    Random _rnd;
     120 
     121  private:
     122
     123    // Implementation of the RANDOM node selection rule.
     124    class RandomSelectionRule
     125    {
     126    private:
     127
     128      // References to the MaxClique class
     129      const BoolVector &_clique;
     130      const IntVector  &_delta;
     131      const BoolVector &_tabu;
     132      Random &_rnd;
     133
     134      // Pivot rule data
     135      int _n;
     136
     137    public:
     138
     139      // Constructor
     140      RandomSelectionRule(MaxClique &mc) :
     141        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
     142        _rnd(mc._rnd), _n(mc._n)
     143      {}
     144
     145      // Return a node index for a feasible add move or -1 if no one exists
     146      int nextFeasibleAddNode() const {
     147        int start_node = _rnd[_n];
     148        for (int i = start_node; i != _n; i++) {
     149          if (_delta[i] == 0 && !_tabu[i]) return i;
     150        }
     151        for (int i = 0; i != start_node; i++) {
     152          if (_delta[i] == 0 && !_tabu[i]) return i;
     153        }
     154        return -1;
     155      }
     156
     157      // Return a node index for a feasible swap move or -1 if no one exists
     158      int nextFeasibleSwapNode() const {
     159        int start_node = _rnd[_n];
     160        for (int i = start_node; i != _n; i++) {
     161          if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
     162        }
     163        for (int i = 0; i != start_node; i++) {
     164          if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i;
     165        }
     166        return -1;
     167      }
     168
     169      // Return a node index for an add move or -1 if no one exists
     170      int nextAddNode() const {
     171        int start_node = _rnd[_n];
     172        for (int i = start_node; i != _n; i++) {
     173          if (_delta[i] == 0) return i;
     174        }
     175        for (int i = 0; i != start_node; i++) {
     176          if (_delta[i] == 0) return i;
     177        }
     178        return -1;
     179      }
     180     
     181      // Update internal data structures between stages (if necessary)
     182      void update() {}
     183
     184    }; //class RandomSelectionRule
     185
     186
     187    // Implementation of the DEGREE_BASED node selection rule.
     188    class DegreeBasedSelectionRule
     189    {
     190    private:
     191
     192      // References to the MaxClique class
     193      const BoolVector &_clique;
     194      const IntVector  &_delta;
     195      const BoolVector &_tabu;
     196      Random &_rnd;
     197
     198      // Pivot rule data
     199      int _n;
     200      IntVector _deg;
     201
     202    public:
     203
     204      // Constructor
     205      DegreeBasedSelectionRule(MaxClique &mc) :
     206        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
     207        _rnd(mc._rnd), _n(mc._n), _deg(_n)
     208      {
     209        for (int i = 0; i != _n; i++) {
     210          int d = 0;
     211          BoolVector &row = mc._gr[i];
     212          for (int j = 0; j != _n; j++) {
     213            if (row[j]) d++;
     214          }
     215          _deg[i] = d;
     216        }
     217      }
     218
     219      // Return a node index for a feasible add move or -1 if no one exists
     220      int nextFeasibleAddNode() const {
     221        int start_node = _rnd[_n];
     222        int node = -1, max_deg = -1;
     223        for (int i = start_node; i != _n; i++) {
     224          if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
     225            node = i;
     226            max_deg = _deg[i];
     227          }
     228        }
     229        for (int i = 0; i != start_node; i++) {
     230          if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) {
     231            node = i;
     232            max_deg = _deg[i];
     233          }
     234        }
     235        return node;
     236      }
     237
     238      // Return a node index for a feasible swap move or -1 if no one exists
     239      int nextFeasibleSwapNode() const {
     240        int start_node = _rnd[_n];
     241        int node = -1, max_deg = -1;
     242        for (int i = start_node; i != _n; i++) {
     243          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
     244              _deg[i] > max_deg) {
     245            node = i;
     246            max_deg = _deg[i];
     247          }
     248        }
     249        for (int i = 0; i != start_node; i++) {
     250          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
     251              _deg[i] > max_deg) {
     252            node = i;
     253            max_deg = _deg[i];
     254          }
     255        }
     256        return node;
     257      }
     258
     259      // Return a node index for an add move or -1 if no one exists
     260      int nextAddNode() const {
     261        int start_node = _rnd[_n];
     262        int node = -1, max_deg = -1;
     263        for (int i = start_node; i != _n; i++) {
     264          if (_delta[i] == 0 && _deg[i] > max_deg) {
     265            node = i;
     266            max_deg = _deg[i];
     267          }
     268        }
     269        for (int i = 0; i != start_node; i++) {
     270          if (_delta[i] == 0 && _deg[i] > max_deg) {
     271            node = i;
     272            max_deg = _deg[i];
     273          }
     274        }
     275        return node;
     276      }
     277     
     278      // Update internal data structures between stages (if necessary)
     279      void update() {}
     280
     281    }; //class DegreeBasedSelectionRule
     282
     283
     284    // Implementation of the PENALTY_BASED node selection rule.
     285    class PenaltyBasedSelectionRule
     286    {
     287    private:
     288
     289      // References to the MaxClique class
     290      const BoolVector &_clique;
     291      const IntVector  &_delta;
     292      const BoolVector &_tabu;
     293      Random &_rnd;
     294
     295      // Pivot rule data
     296      int _n;
     297      IntVector _penalty;
     298
     299    public:
     300
     301      // Constructor
     302      PenaltyBasedSelectionRule(MaxClique &mc) :
     303        _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu),
     304        _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0)
     305      {}
     306
     307      // Return a node index for a feasible add move or -1 if no one exists
     308      int nextFeasibleAddNode() const {
     309        int start_node = _rnd[_n];
     310        int node = -1, min_p = std::numeric_limits<int>::max();
     311        for (int i = start_node; i != _n; i++) {
     312          if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
     313            node = i;
     314            min_p = _penalty[i];
     315          }
     316        }
     317        for (int i = 0; i != start_node; i++) {
     318          if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) {
     319            node = i;
     320            min_p = _penalty[i];
     321          }
     322        }
     323        return node;
     324      }
     325
     326      // Return a node index for a feasible swap move or -1 if no one exists
     327      int nextFeasibleSwapNode() const {
     328        int start_node = _rnd[_n];
     329        int node = -1, min_p = std::numeric_limits<int>::max();
     330        for (int i = start_node; i != _n; i++) {
     331          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
     332              _penalty[i] < min_p) {
     333            node = i;
     334            min_p = _penalty[i];
     335          }
     336        }
     337        for (int i = 0; i != start_node; i++) {
     338          if (!_clique[i] && _delta[i] == 1 && !_tabu[i] &&
     339              _penalty[i] < min_p) {
     340            node = i;
     341            min_p = _penalty[i];
     342          }
     343        }
     344        return node;
     345      }
     346
     347      // Return a node index for an add move or -1 if no one exists
     348      int nextAddNode() const {
     349        int start_node = _rnd[_n];
     350        int node = -1, min_p = std::numeric_limits<int>::max();
     351        for (int i = start_node; i != _n; i++) {
     352          if (_delta[i] == 0 && _penalty[i] < min_p) {
     353            node = i;
     354            min_p = _penalty[i];
     355          }
     356        }
     357        for (int i = 0; i != start_node; i++) {
     358          if (_delta[i] == 0 && _penalty[i] < min_p) {
     359            node = i;
     360            min_p = _penalty[i];
     361          }
     362        }
     363        return node;
     364      }
     365     
     366      // Update internal data structures between stages (if necessary)
     367      void update() {}
     368
     369    }; //class PenaltyBasedSelectionRule
     370
     371  public:
     372
     373    /// \brief Constructor.
     374    ///
     375    /// Constructor.
     376    /// The global \ref rnd "random number generator instance" is used
     377    /// during the algorithm.
     378    ///
     379    /// \param graph The undirected graph the algorithm runs on.
     380    MaxClique(const GR& graph) :
     381      _graph(graph), _id(_graph), _rnd(rnd)
     382    {}
     383   
     384    /// \brief Constructor with random seed.
     385    ///
     386    /// Constructor with random seed.
     387    ///
     388    /// \param graph The undirected graph the algorithm runs on.
     389    /// \param seed Seed value for the internal random number generator
     390    /// that is used during the algorithm.
     391    MaxClique(const GR& graph, int seed) :
     392      _graph(graph), _id(_graph), _rnd(seed)
     393    {}
     394   
     395    /// \brief Constructor with random number generator.
     396    ///
     397    /// Constructor with random number generator.
     398    ///
     399    /// \param graph The undirected graph the algorithm runs on.
     400    /// \param random A random number generator that is used during the
     401    /// algorithm.
     402    MaxClique(const GR& graph, const Random& random) :
     403      _graph(graph), _id(_graph), _rnd(random)
     404    {}
     405   
     406    /// \name Execution Control
     407    /// @{
     408
     409    /// \brief Runs the algorithm.
     410    ///
     411    /// This function runs the algorithm.
     412    ///
     413    /// \param step_num The maximum number of node selections (steps)
     414    /// during the search process.
     415    /// This parameter controls the running time and the success of the
     416    /// algorithm. For larger values, the algorithm runs slower but it more
     417    /// likely finds larger cliques. For smaller values, the algorithm is
     418    /// faster but probably gives worse results.
     419    /// \param rule The node selection rule. For more information, see
     420    /// \ref SelectionRule.
     421    /// 
     422    /// \return The size of the found clique.
     423    int run(int step_num = 100000,
     424            SelectionRule rule = PENALTY_BASED)
     425    {
     426      switch (rule) {
     427        case RANDOM:
     428          return start<RandomSelectionRule>(step_num);
     429        case DEGREE_BASED:
     430          return start<DegreeBasedSelectionRule>(step_num);
     431        case PENALTY_BASED:
     432          return start<PenaltyBasedSelectionRule>(step_num);
     433      }
     434      return 0; // avoid warning
     435    }
     436
     437    /// @}
     438
     439    /// \name Query Functions
     440    /// @{
     441   
     442    /// \brief The size of the found clique
     443    ///
     444    /// This function returns the size of the found clique.
     445    ///
     446    /// \pre run() must be called before using this function.
     447    int cliqueSize() const {
     448      return _best_size;
     449    }
     450   
     451    /// \brief Gives back the found clique in a \c bool node map
     452    ///
     453    /// This function gives back the characteristic vector of the found
     454    /// clique in the given node map.
     455    /// It must be a \ref concepts::WriteMap "writable" node map with
     456    /// \c bool (or convertible) value type.
     457    ///
     458    /// \pre run() must be called before using this function.
     459    template <typename CliqueMap>
     460    void cliqueMap(CliqueMap &map) const {
     461      for (NodeIt n(_graph); n != INVALID; ++n) {
     462        map[n] = static_cast<bool>(_best_clique[_id[n]]);
     463      }
     464    }
     465   
     466    /// @}
     467 
     468  private:
     469
     470    // Adds a node to the current clique
     471    void addCliqueNode(int u) {
     472      if (_clique[u]) return;
     473      _clique[u] = true;
     474      _size++;
     475      BoolVector &row = _gr[u];
     476      for (int i = 0; i != _n; i++) {
     477        if (!row[i]) _delta[i]++;
     478      }
     479    }
     480
     481    // Removes a node from the current clique
     482    void delCliqueNode(int u) {
     483      if (!_clique[u]) return;
     484      _clique[u] = false;
     485      _size--;
     486      BoolVector &row = _gr[u];
     487      for (int i = 0; i != _n; i++) {
     488        if (!row[i]) _delta[i]--;
     489      }
     490    }
     491
     492    // Executes the algorithm
     493    template <typename SelectionRuleImpl>
     494    int start(int max_select) {
     495      // Options for the restart rule
     496      const bool delta_based_restart = true;
     497      const int restart_delta_limit = 4;
     498     
     499      // Initialize data structures
     500      _n = countNodes(_graph);
     501      int ui = 0;
     502      for (NodeIt u(_graph); u != INVALID; ++u) {
     503        _id[u] = ui++;
     504      }
     505      _gr.clear();
     506      _gr.resize(_n, BoolVector(_n, false));
     507      ui = 0;
     508      for (NodeIt u(_graph); u != INVALID; ++u) {
     509        for (IncEdgeIt e(_graph, u); e != INVALID; ++e) {
     510          int vi = _id[_graph.runningNode(e)];
     511          _gr[ui][vi] = true;
     512          _gr[vi][ui] = true;
     513        }
     514        ++ui;
     515      }
     516     
     517      _clique.clear();
     518      _clique.resize(_n, false);
     519      _size = 0;
     520      _best_clique.clear();
     521      _best_clique.resize(_n, false);
     522      _best_size = 0;
     523      _delta.clear();
     524      _delta.resize(_n, 0);
     525      _tabu.clear();
     526      _tabu.resize(_n, false);
     527
     528      if (_n == 0) return 0;
     529      if (_n == 1) {
     530        _best_clique[0] = true;
     531        _best_size = 1;
     532        return _best_size;
     533      }
     534
     535      // Iterated local search
     536      SelectionRuleImpl sel_method(*this);
     537      int select = 0;
     538      IntVector restart_nodes;
     539
     540      while (select < max_select) {
     541
     542        // Perturbation/restart
     543        if (delta_based_restart) {
     544          restart_nodes.clear();
     545          for (int i = 0; i != _n; i++) {
     546            if (_delta[i] >= restart_delta_limit)
     547              restart_nodes.push_back(i);
     548          }
     549        }
     550        int rs_node = -1;
     551        if (restart_nodes.size() > 0) {
     552          rs_node = restart_nodes[_rnd[restart_nodes.size()]];
     553        } else {
     554          rs_node = _rnd[_n];     
     555        }
     556        BoolVector &row = _gr[rs_node];
     557        for (int i = 0; i != _n; i++) {
     558          if (_clique[i] && !row[i]) delCliqueNode(i);
     559        }
     560        addCliqueNode(rs_node);
     561
     562        // Local search
     563        _tabu.clear();
     564        _tabu.resize(_n, false);
     565        bool tabu_empty = true;
     566        int max_swap = _size;
     567        while (select < max_select) {
     568          select++;
     569          int u;
     570          if ((u = sel_method.nextFeasibleAddNode()) != -1) {
     571            // Feasible add move
     572            addCliqueNode(u);
     573            if (tabu_empty) max_swap = _size;
     574          }
     575          else if ((u = sel_method.nextFeasibleSwapNode()) != -1) {
     576            // Feasible swap move
     577            int v = -1;
     578            BoolVector &row = _gr[u];
     579            for (int i = 0; i != _n; i++) {
     580              if (_clique[i] && !row[i]) {
     581                v = i;
     582                break;
     583              }
     584            }
     585            addCliqueNode(u);
     586            delCliqueNode(v);
     587            _tabu[v] = true;
     588            tabu_empty = false;
     589            if (--max_swap <= 0) break;
     590          }
     591          else if ((u = sel_method.nextAddNode()) != -1) {
     592            // Non-feasible add move
     593            addCliqueNode(u);
     594          }
     595          else break;
     596        }
     597        if (_size > _best_size) {
     598          _best_clique = _clique;
     599          _best_size = _size;
     600          if (_best_size == _n) return _best_size;
     601        }
     602        sel_method.update();
     603      }
     604     
     605      return _best_size;
     606    }
     607
     608  }; //class MaxClique
     609
     610  ///@}
     611
     612} //namespace lemon
     613
     614                                                               
     615#endif //LEMON_MAX_CLIQUE_H
  • test/CMakeLists.txt

    diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
    a b  
    3131  kruskal_test
    3232  maps_test
    3333  matching_test
     34  max_clique_test
    3435  min_cost_arborescence_test
    3536  min_cost_flow_test
    3637  min_mean_cycle_test
  • test/Makefile.am

    diff --git a/test/Makefile.am b/test/Makefile.am
    a b  
    3333        test/kruskal_test \
    3434        test/maps_test \
    3535        test/matching_test \
     36        test/max_clique_test \
    3637        test/min_cost_arborescence_test \
    3738        test/min_cost_flow_test \
    3839        test/min_mean_cycle_test \
     
    8485test_maps_test_SOURCES = test/maps_test.cc
    8586test_mip_test_SOURCES = test/mip_test.cc
    8687test_matching_test_SOURCES = test/matching_test.cc
     88test_max_clique_test_SOURCES = test/max_clique_test.cc
    8789test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc
    8890test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
    8991test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc
  • new file test/max_clique_test.cc

    diff --git a/test/max_clique_test.cc b/test/max_clique_test.cc
    new file mode 100644
    - +  
     1/* -*- mode: C++; indent-tabs-mode: nil; -*-
     2 *
     3 * This file is a part of LEMON, a generic C++ optimization library.
     4 *
     5 * Copyright (C) 2003-2010
     6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8 *
     9 * Permission to use, modify and distribute this software is granted
     10 * provided that this copyright notice appears in all copies. For
     11 * precise terms see the accompanying LICENSE file.
     12 *
     13 * This software is provided "AS IS" with no warranty of any kind,
     14 * express or implied, and with no claim as to its suitability for any
     15 * purpose.
     16 *
     17 */
     18
     19#include <sstream>
     20#include <lemon/list_graph.h>
     21#include <lemon/full_graph.h>
     22#include <lemon/grid_graph.h>
     23#include <lemon/lgf_reader.h>
     24#include <lemon/max_clique.h>
     25
     26#include "test_tools.h"
     27
     28using namespace lemon;
     29
     30char test_lgf[] =
     31  "@nodes\n"
     32  "label max_clique\n"
     33  "1     0\n"
     34  "2     0\n"
     35  "3     0\n"
     36  "4     1\n"
     37  "5     1\n"
     38  "6     1\n"
     39  "7     1\n"
     40  "@edges\n"
     41  "    label\n"
     42  "1 2     1\n"
     43  "1 3     2\n"
     44  "1 4     3\n"
     45  "1 6     4\n"
     46  "2 3     5\n"
     47  "2 5     6\n"
     48  "2 7     7\n"
     49  "3 4     8\n"
     50  "3 5     9\n"
     51  "4 5    10\n"
     52  "4 6    11\n"
     53  "4 7    12\n"
     54  "5 6    13\n"
     55  "5 7    14\n"
     56  "6 7    15\n";
     57     
     58
     59// Check with general graphs
     60template <typename Param>
     61void checkMaxCliqueGeneral(int max_sel, Param rule) {
     62  // Basic tests
     63  {
     64    ListGraph g;
     65    ListGraph::NodeMap<bool> map(g);
     66    MaxClique<ListGraph> mc(g);
     67    check(mc.run(max_sel, rule) == 0, "Wrong clique size");
     68    check(mc.cliqueSize() == 0, "Wrong clique size");
     69
     70    ListGraph::Node u = g.addNode();
     71    check(mc.run(max_sel, rule) == 1, "Wrong clique size");
     72    check(mc.cliqueSize() == 1, "Wrong clique size");
     73    mc.cliqueMap(map);
     74    check(map[u], "Wrong clique map");
     75   
     76    ListGraph::Node v = g.addNode();
     77    check(mc.run(max_sel, rule) == 1, "Wrong clique size");
     78    check(mc.cliqueSize() == 1, "Wrong clique size");
     79    mc.cliqueMap(map);
     80    check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map");
     81
     82    g.addEdge(u, v);
     83    check(mc.run(max_sel, rule) == 2, "Wrong clique size");
     84    check(mc.cliqueSize() == 2, "Wrong clique size");
     85    mc.cliqueMap(map);
     86    check(map[u] && map[v], "Wrong clique map");
     87  }
     88
     89  // Test graph
     90  {
     91    ListGraph g;
     92    ListGraph::NodeMap<bool> max_clique(g);
     93    ListGraph::NodeMap<bool> map(g);
     94    std::istringstream input(test_lgf);
     95    graphReader(g, input)
     96      .nodeMap("max_clique", max_clique)
     97      .run();
     98   
     99    MaxClique<ListGraph> mc(g);
     100    check(mc.run(max_sel, rule) == 4, "Wrong clique size");
     101    check(mc.cliqueSize() == 4, "Wrong clique size");
     102    mc.cliqueMap(map);
     103    for (ListGraph::NodeIt n(g); n != INVALID; ++n) {
     104      check(map[n] == max_clique[n], "Wrong clique map");
     105    }
     106  }
     107}
     108
     109// Check with full graphs
     110template <typename Param>
     111void checkMaxCliqueFullGraph(int max_sel, Param rule) {
     112  for (int size = 0; size <= 40; size = size * 3 + 1) {
     113    FullGraph g(size);
     114    FullGraph::NodeMap<bool> map(g);
     115    MaxClique<FullGraph> mc(g);
     116    check(mc.run(max_sel, rule) == size, "Wrong clique size");
     117    check(mc.cliqueSize() == size, "Wrong clique size");
     118    mc.cliqueMap(map);
     119    for (FullGraph::NodeIt n(g); n != INVALID; ++n) {
     120      check(map[n], "Wrong clique map");
     121    }
     122  }
     123}
     124
     125// Check with grid graphs
     126template <typename Param>
     127void checkMaxCliqueGridGraph(int max_sel, Param rule) {
     128  GridGraph g(5, 7);
     129  GridGraph::NodeMap<char> map(g);
     130  MaxClique<GridGraph> mc(g);
     131  check(mc.run(max_sel, rule) == 2, "Wrong clique size");
     132  check(mc.cliqueSize() == 2, "Wrong clique size");
     133}
     134
     135
     136int main() {
     137  checkMaxCliqueGeneral(50, MaxClique<ListGraph>::RANDOM);
     138  checkMaxCliqueGeneral(50, MaxClique<ListGraph>::DEGREE_BASED);
     139  checkMaxCliqueGeneral(50, MaxClique<ListGraph>::PENALTY_BASED);
     140
     141  checkMaxCliqueFullGraph(50, MaxClique<FullGraph>::RANDOM);
     142  checkMaxCliqueFullGraph(50, MaxClique<FullGraph>::DEGREE_BASED);
     143  checkMaxCliqueFullGraph(50, MaxClique<FullGraph>::PENALTY_BASED);
     144                       
     145  checkMaxCliqueGridGraph(50, MaxClique<GridGraph>::RANDOM);
     146  checkMaxCliqueGridGraph(50, MaxClique<GridGraph>::DEGREE_BASED);
     147  checkMaxCliqueGridGraph(50, MaxClique<GridGraph>::PENALTY_BASED);
     148                       
     149  return 0;
     150}