COIN-OR::LEMON - Graph Library

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

File 380-max-clique-c279b19abc62.patch, 28.2 KB (added by Peter Kovacs, 10 years ago)
  • doc/groups.dox

    # HG changeset patch
    # User Peter Kovacs <kpeter@inf.elte.hu>
    # Date 1279859377 -7200
    # Node ID c279b19abc62e8e4af4f66240cd22186284749e4
    # Parent  24b3f18ed9e2bea99ab482c493c3db769362ecf0
    Add a heuristic algorithm for the max clique problem (#380)
    
    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
    558558This group contains the approximation and heuristic algorithms
    559559implemented in LEMON.
     560
     561<b>Maximum Clique Problem</b>
     562  - \ref GrossoLocatelliPullanMc An efficient heuristic algorithm of
     563    Grosso, Locatelli, and Pullan.
    560564*/
    561565
    562566/**
  • 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  
    9090        lemon/gomory_hu.h \
    9191        lemon/graph_to_eps.h \
    9292        lemon/grid_graph.h \
     93        lemon/grosso_locatelli_pullan_mc.h \
    9394        lemon/hartmann_orlin_mmc.h \
    9495        lemon/howard_mmc.h \
    9596        lemon/hypercube_graph.h \
  • new file lemon/grosso_locatelli_pullan_mc.h

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