lemon/bits/alteration_notifier.h
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 03 Apr 2009 18:59:15 +0200
changeset 600 6ac5d9ae1d3d
parent 361 f58410582b9b
permissions -rw-r--r--
Support real types + numerical stability fix in NS (#254)

- Real types are supported by appropriate inicialization.
- A feature of the XTI spanning tree structure is removed to ensure
numerical stability (could cause problems using integer types).
The node potentials are updated always on the lower subtree,
in order to prevent overflow problems.
The former method isn't notably faster during to our tests.
alpar@209
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@57
     2
 *
alpar@209
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@57
     4
 *
alpar@440
     5
 * Copyright (C) 2003-2009
deba@57
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@57
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@57
     8
 *
deba@57
     9
 * Permission to use, modify and distribute this software is granted
deba@57
    10
 * provided that this copyright notice appears in all copies. For
deba@57
    11
 * precise terms see the accompanying LICENSE file.
deba@57
    12
 *
deba@57
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@57
    14
 * express or implied, and with no claim as to its suitability for any
deba@57
    15
 * purpose.
deba@57
    16
 *
deba@57
    17
 */
deba@57
    18
deba@57
    19
#ifndef LEMON_BITS_ALTERATION_NOTIFIER_H
deba@57
    20
#define LEMON_BITS_ALTERATION_NOTIFIER_H
deba@57
    21
deba@57
    22
#include <vector>
deba@57
    23
#include <list>
deba@57
    24
deba@220
    25
#include <lemon/core.h>
deba@57
    26
kpeter@314
    27
//\ingroup graphbits
kpeter@314
    28
//\file
kpeter@314
    29
//\brief Observer notifier for graph alteration observers.
deba@57
    30
deba@57
    31
namespace lemon {
deba@57
    32
kpeter@314
    33
  // \ingroup graphbits
kpeter@314
    34
  //
kpeter@314
    35
  // \brief Notifier class to notify observes about alterations in
kpeter@314
    36
  // a container.
kpeter@314
    37
  //
kpeter@361
    38
  // The simple graphs can be refered as two containers: a node container
kpeter@361
    39
  // and an edge container. But they do not store values directly, they
kpeter@361
    40
  // are just key continars for more value containers, which are the
kpeter@361
    41
  // node and edge maps.
kpeter@314
    42
  //
kpeter@361
    43
  // The node and edge sets of the graphs can be changed as we add or erase
kpeter@314
    44
  // nodes and edges in the graph. LEMON would like to handle easily
kpeter@314
    45
  // that the node and edge maps should contain values for all nodes or
kpeter@314
    46
  // edges. If we want to check on every indicing if the map contains
kpeter@314
    47
  // the current indicing key that cause a drawback in the performance
kpeter@361
    48
  // in the library. We use another solution: we notify all maps about
kpeter@314
    49
  // an alteration in the graph, which cause only drawback on the
kpeter@314
    50
  // alteration of the graph.
kpeter@314
    51
  //
kpeter@361
    52
  // This class provides an interface to a node or edge container.
kpeter@361
    53
  // The first() and next() member functions make possible
kpeter@361
    54
  // to iterate on the keys of the container.
kpeter@361
    55
  // The id() function returns an integer id for each key.
kpeter@361
    56
  // The maxId() function gives back an upper bound of the ids.
kpeter@314
    57
  //
kpeter@314
    58
  // For the proper functonality of this class, we should notify it
kpeter@361
    59
  // about each alteration in the container. The alterations have four type:
kpeter@361
    60
  // add(), erase(), build() and clear(). The add() and
kpeter@361
    61
  // erase() signal that only one or few items added or erased to or
kpeter@361
    62
  // from the graph. If all items are erased from the graph or if a new graph
kpeter@361
    63
  // is built from an empty graph, then it can be signaled with the
kpeter@314
    64
  // clear() and build() members. Important rule that if we erase items
kpeter@361
    65
  // from graphs we should first signal the alteration and after that erase
kpeter@314
    66
  // them from the container, on the other way on item addition we should
kpeter@314
    67
  // first extend the container and just after that signal the alteration.
kpeter@314
    68
  //
kpeter@314
    69
  // The alteration can be observed with a class inherited from the
kpeter@361
    70
  // ObserverBase nested class. The signals can be handled with
kpeter@314
    71
  // overriding the virtual functions defined in the base class.  The
kpeter@314
    72
  // observer base can be attached to the notifier with the
kpeter@361
    73
  // attach() member and can be detached with detach() function. The
kpeter@314
    74
  // alteration handlers should not call any function which signals
kpeter@314
    75
  // an other alteration in the same notifier and should not
kpeter@314
    76
  // detach any observer from the notifier.
kpeter@314
    77
  //
kpeter@361
    78
  // Alteration observers try to be exception safe. If an add() or
kpeter@361
    79
  // a clear() function throws an exception then the remaining
kpeter@314
    80
  // observeres will not be notified and the fulfilled additions will
kpeter@361
    81
  // be rolled back by calling the erase() or clear() functions.
kpeter@361
    82
  // Hence erase() and clear() should not throw exception.
kpeter@361
    83
  // Actullay, they can throw only \ref ImmediateDetach exception,
kpeter@361
    84
  // which detach the observer from the notifier.
kpeter@314
    85
  //
kpeter@361
    86
  // There are some cases, when the alteration observing is not completly
kpeter@314
    87
  // reliable. If we want to carry out the node degree in the graph
kpeter@361
    88
  // as in the \ref InDegMap and we use the reverseArc(), then it cause
kpeter@314
    89
  // unreliable functionality. Because the alteration observing signals
kpeter@361
    90
  // only erasing and adding but not the reversing, it will stores bad
kpeter@361
    91
  // degrees. Apart form that the subgraph adaptors cannot even signal
kpeter@361
    92
  // the alterations because just a setting in the filter map can modify
kpeter@361
    93
  // the graph and this cannot be watched in any way.
kpeter@314
    94
  //
kpeter@314
    95
  // \param _Container The container which is observed.
kpeter@314
    96
  // \param _Item The item type which is obserbved.
deba@57
    97
deba@57
    98
  template <typename _Container, typename _Item>
deba@57
    99
  class AlterationNotifier {
deba@57
   100
  public:
deba@57
   101
deba@57
   102
    typedef True Notifier;
deba@57
   103
deba@57
   104
    typedef _Container Container;
deba@57
   105
    typedef _Item Item;
deba@57
   106
kpeter@361
   107
    // \brief Exception which can be called from clear() and
kpeter@361
   108
    // erase().
kpeter@314
   109
    //
kpeter@361
   110
    // From the clear() and erase() function only this
kpeter@314
   111
    // exception is allowed to throw. The exception immediatly
kpeter@314
   112
    // detaches the current observer from the notifier. Because the
kpeter@361
   113
    // clear() and erase() should not throw other exceptions
kpeter@314
   114
    // it can be used to invalidate the observer.
deba@57
   115
    struct ImmediateDetach {};
deba@57
   116
kpeter@314
   117
    // \brief ObserverBase is the base class for the observers.
kpeter@314
   118
    //
kpeter@314
   119
    // ObserverBase is the abstract base class for the observers.
kpeter@314
   120
    // It will be notified about an item was inserted into or
kpeter@314
   121
    // erased from the graph.
kpeter@314
   122
    //
kpeter@314
   123
    // The observer interface contains some pure virtual functions
kpeter@314
   124
    // to override. The add() and erase() functions are
kpeter@361
   125
    // to notify the oberver when one item is added or erased.
kpeter@314
   126
    //
kpeter@314
   127
    // The build() and clear() members are to notify the observer
kpeter@314
   128
    // about the container is built from an empty container or
kpeter@314
   129
    // is cleared to an empty container.
deba@57
   130
    class ObserverBase {
deba@57
   131
    protected:
deba@57
   132
      typedef AlterationNotifier Notifier;
deba@57
   133
deba@57
   134
      friend class AlterationNotifier;
deba@57
   135
kpeter@314
   136
      // \brief Default constructor.
kpeter@314
   137
      //
kpeter@314
   138
      // Default constructor for ObserverBase.
deba@57
   139
      ObserverBase() : _notifier(0) {}
deba@57
   140
kpeter@314
   141
      // \brief Constructor which attach the observer into notifier.
kpeter@314
   142
      //
kpeter@314
   143
      // Constructor which attach the observer into notifier.
deba@57
   144
      ObserverBase(AlterationNotifier& nf) {
deba@57
   145
        attach(nf);
deba@57
   146
      }
deba@57
   147
kpeter@314
   148
      // \brief Constructor which attach the obserever to the same notifier.
kpeter@314
   149
      //
kpeter@314
   150
      // Constructor which attach the obserever to the same notifier as
kpeter@314
   151
      // the other observer is attached to.
deba@57
   152
      ObserverBase(const ObserverBase& copy) {
alpar@209
   153
        if (copy.attached()) {
deba@57
   154
          attach(*copy.notifier());
alpar@209
   155
        }
deba@57
   156
      }
alpar@209
   157
kpeter@314
   158
      // \brief Destructor
deba@57
   159
      virtual ~ObserverBase() {
deba@57
   160
        if (attached()) {
deba@57
   161
          detach();
deba@57
   162
        }
deba@57
   163
      }
deba@57
   164
kpeter@314
   165
      // \brief Attaches the observer into an AlterationNotifier.
kpeter@314
   166
      //
kpeter@314
   167
      // This member attaches the observer into an AlterationNotifier.
deba@57
   168
      void attach(AlterationNotifier& nf) {
alpar@209
   169
        nf.attach(*this);
deba@57
   170
      }
alpar@209
   171
kpeter@314
   172
      // \brief Detaches the observer into an AlterationNotifier.
kpeter@314
   173
      //
kpeter@314
   174
      // This member detaches the observer from an AlterationNotifier.
deba@57
   175
      void detach() {
deba@57
   176
        _notifier->detach(*this);
deba@57
   177
      }
alpar@209
   178
kpeter@314
   179
      // \brief Gives back a pointer to the notifier which the map
kpeter@314
   180
      // attached into.
kpeter@314
   181
      //
kpeter@314
   182
      // This function gives back a pointer to the notifier which the map
kpeter@314
   183
      // attached into.
deba@57
   184
      Notifier* notifier() const { return const_cast<Notifier*>(_notifier); }
alpar@209
   185
kpeter@314
   186
      // Gives back true when the observer is attached into a notifier.
deba@57
   187
      bool attached() const { return _notifier != 0; }
deba@57
   188
deba@57
   189
    private:
deba@57
   190
deba@57
   191
      ObserverBase& operator=(const ObserverBase& copy);
deba@57
   192
deba@57
   193
    protected:
alpar@209
   194
deba@57
   195
      Notifier* _notifier;
deba@57
   196
      typename std::list<ObserverBase*>::iterator _index;
deba@57
   197
kpeter@314
   198
      // \brief The member function to notificate the observer about an
kpeter@314
   199
      // item is added to the container.
kpeter@314
   200
      //
kpeter@314
   201
      // The add() member function notificates the observer about an item
kpeter@314
   202
      // is added to the container. It have to be overrided in the
kpeter@314
   203
      // subclasses.
deba@57
   204
      virtual void add(const Item&) = 0;
deba@57
   205
kpeter@314
   206
      // \brief The member function to notificate the observer about
kpeter@314
   207
      // more item is added to the container.
kpeter@314
   208
      //
kpeter@314
   209
      // The add() member function notificates the observer about more item
kpeter@314
   210
      // is added to the container. It have to be overrided in the
kpeter@314
   211
      // subclasses.
deba@57
   212
      virtual void add(const std::vector<Item>& items) = 0;
deba@57
   213
kpeter@314
   214
      // \brief The member function to notificate the observer about an
kpeter@314
   215
      // item is erased from the container.
kpeter@314
   216
      //
kpeter@314
   217
      // The erase() member function notificates the observer about an
kpeter@314
   218
      // item is erased from the container. It have to be overrided in
kpeter@314
   219
      // the subclasses.
deba@57
   220
      virtual void erase(const Item&) = 0;
deba@57
   221
kpeter@314
   222
      // \brief The member function to notificate the observer about
kpeter@314
   223
      // more item is erased from the container.
kpeter@314
   224
      //
kpeter@314
   225
      // The erase() member function notificates the observer about more item
kpeter@314
   226
      // is erased from the container. It have to be overrided in the
kpeter@314
   227
      // subclasses.
deba@57
   228
      virtual void erase(const std::vector<Item>& items) = 0;
deba@57
   229
kpeter@314
   230
      // \brief The member function to notificate the observer about the
kpeter@314
   231
      // container is built.
kpeter@314
   232
      //
kpeter@314
   233
      // The build() member function notificates the observer about the
kpeter@314
   234
      // container is built from an empty container. It have to be
kpeter@314
   235
      // overrided in the subclasses.
deba@57
   236
      virtual void build() = 0;
deba@57
   237
kpeter@314
   238
      // \brief The member function to notificate the observer about all
kpeter@314
   239
      // items are erased from the container.
kpeter@314
   240
      //
kpeter@314
   241
      // The clear() member function notificates the observer about all
kpeter@314
   242
      // items are erased from the container. It have to be overrided in
kpeter@314
   243
      // the subclasses.
deba@57
   244
      virtual void clear() = 0;
deba@57
   245
deba@57
   246
    };
alpar@209
   247
deba@57
   248
  protected:
deba@57
   249
deba@57
   250
    const Container* container;
deba@57
   251
alpar@209
   252
    typedef std::list<ObserverBase*> Observers;
deba@57
   253
    Observers _observers;
deba@57
   254
alpar@209
   255
deba@57
   256
  public:
deba@57
   257
kpeter@314
   258
    // \brief Default constructor.
kpeter@314
   259
    //
kpeter@314
   260
    // The default constructor of the AlterationNotifier.
kpeter@314
   261
    // It creates an empty notifier.
alpar@209
   262
    AlterationNotifier()
deba@57
   263
      : container(0) {}
deba@57
   264
kpeter@314
   265
    // \brief Constructor.
kpeter@314
   266
    //
kpeter@314
   267
    // Constructor with the observed container parameter.
alpar@209
   268
    AlterationNotifier(const Container& _container)
deba@57
   269
      : container(&_container) {}
deba@57
   270
kpeter@314
   271
    // \brief Copy Constructor of the AlterationNotifier.
kpeter@314
   272
    //
kpeter@314
   273
    // Copy constructor of the AlterationNotifier.
kpeter@314
   274
    // It creates only an empty notifier because the copiable
kpeter@314
   275
    // notifier's observers have to be registered still into that notifier.
alpar@209
   276
    AlterationNotifier(const AlterationNotifier& _notifier)
deba@57
   277
      : container(_notifier.container) {}
deba@57
   278
kpeter@314
   279
    // \brief Destructor.
kpeter@314
   280
    //
kpeter@314
   281
    // Destructor of the AlterationNotifier.
deba@57
   282
    ~AlterationNotifier() {
deba@57
   283
      typename Observers::iterator it;
deba@57
   284
      for (it = _observers.begin(); it != _observers.end(); ++it) {
alpar@209
   285
        (*it)->_notifier = 0;
deba@57
   286
      }
deba@57
   287
    }
deba@57
   288
kpeter@314
   289
    // \brief Sets the container.
kpeter@314
   290
    //
kpeter@314
   291
    // Sets the container.
deba@57
   292
    void setContainer(const Container& _container) {
deba@57
   293
      container = &_container;
deba@57
   294
    }
deba@57
   295
deba@57
   296
  protected:
deba@57
   297
deba@57
   298
    AlterationNotifier& operator=(const AlterationNotifier&);
deba@57
   299
deba@57
   300
  public:
deba@57
   301
kpeter@314
   302
    // \brief First item in the container.
kpeter@314
   303
    //
kpeter@314
   304
    // Returns the first item in the container. It is
kpeter@314
   305
    // for start the iteration on the container.
deba@57
   306
    void first(Item& item) const {
deba@57
   307
      container->first(item);
deba@57
   308
    }
deba@57
   309
kpeter@314
   310
    // \brief Next item in the container.
kpeter@314
   311
    //
kpeter@314
   312
    // Returns the next item in the container. It is
kpeter@314
   313
    // for iterate on the container.
deba@57
   314
    void next(Item& item) const {
deba@57
   315
      container->next(item);
deba@57
   316
    }
deba@57
   317
kpeter@314
   318
    // \brief Returns the id of the item.
kpeter@314
   319
    //
kpeter@314
   320
    // Returns the id of the item provided by the container.
deba@57
   321
    int id(const Item& item) const {
deba@57
   322
      return container->id(item);
deba@57
   323
    }
deba@57
   324
kpeter@314
   325
    // \brief Returns the maximum id of the container.
kpeter@314
   326
    //
kpeter@314
   327
    // Returns the maximum id of the container.
deba@57
   328
    int maxId() const {
deba@57
   329
      return container->maxId(Item());
deba@57
   330
    }
alpar@209
   331
deba@57
   332
  protected:
deba@57
   333
deba@57
   334
    void attach(ObserverBase& observer) {
deba@57
   335
      observer._index = _observers.insert(_observers.begin(), &observer);
deba@57
   336
      observer._notifier = this;
alpar@209
   337
    }
deba@57
   338
deba@57
   339
    void detach(ObserverBase& observer) {
deba@57
   340
      _observers.erase(observer._index);
deba@57
   341
      observer._index = _observers.end();
deba@57
   342
      observer._notifier = 0;
deba@57
   343
    }
deba@57
   344
deba@57
   345
  public:
alpar@209
   346
kpeter@314
   347
    // \brief Notifies all the registed observers about an item added to
kpeter@314
   348
    // the container.
kpeter@314
   349
    //
kpeter@314
   350
    // It notifies all the registed observers about an item added to
kpeter@314
   351
    // the container.
deba@57
   352
    void add(const Item& item) {
deba@57
   353
      typename Observers::reverse_iterator it;
deba@57
   354
      try {
deba@57
   355
        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
deba@57
   356
          (*it)->add(item);
deba@57
   357
        }
deba@57
   358
      } catch (...) {
deba@57
   359
        typename Observers::iterator jt;
deba@57
   360
        for (jt = it.base(); jt != _observers.end(); ++jt) {
deba@57
   361
          (*jt)->erase(item);
deba@57
   362
        }
deba@57
   363
        throw;
deba@57
   364
      }
alpar@209
   365
    }
deba@57
   366
kpeter@314
   367
    // \brief Notifies all the registed observers about more item added to
kpeter@314
   368
    // the container.
kpeter@314
   369
    //
kpeter@314
   370
    // It notifies all the registed observers about more item added to
kpeter@314
   371
    // the container.
deba@57
   372
    void add(const std::vector<Item>& items) {
deba@57
   373
      typename Observers::reverse_iterator it;
deba@57
   374
      try {
deba@57
   375
        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
deba@57
   376
          (*it)->add(items);
deba@57
   377
        }
deba@57
   378
      } catch (...) {
deba@57
   379
        typename Observers::iterator jt;
deba@57
   380
        for (jt = it.base(); jt != _observers.end(); ++jt) {
deba@57
   381
          (*jt)->erase(items);
deba@57
   382
        }
deba@57
   383
        throw;
deba@57
   384
      }
alpar@209
   385
    }
deba@57
   386
kpeter@314
   387
    // \brief Notifies all the registed observers about an item erased from
kpeter@314
   388
    // the container.
kpeter@314
   389
    //
kpeter@314
   390
    // It notifies all the registed observers about an item erased from
kpeter@314
   391
    // the container.
deba@57
   392
    void erase(const Item& item) throw() {
deba@57
   393
      typename Observers::iterator it = _observers.begin();
deba@57
   394
      while (it != _observers.end()) {
deba@57
   395
        try {
deba@57
   396
          (*it)->erase(item);
deba@57
   397
          ++it;
deba@57
   398
        } catch (const ImmediateDetach&) {
deba@57
   399
          (*it)->_index = _observers.end();
deba@57
   400
          (*it)->_notifier = 0;
deba@230
   401
          it = _observers.erase(it);
deba@57
   402
        }
deba@57
   403
      }
deba@57
   404
    }
deba@57
   405
kpeter@314
   406
    // \brief Notifies all the registed observers about more item erased
kpeter@314
   407
    // from the container.
kpeter@314
   408
    //
kpeter@314
   409
    // It notifies all the registed observers about more item erased from
kpeter@314
   410
    // the container.
deba@57
   411
    void erase(const std::vector<Item>& items) {
deba@57
   412
      typename Observers::iterator it = _observers.begin();
deba@57
   413
      while (it != _observers.end()) {
deba@57
   414
        try {
deba@57
   415
          (*it)->erase(items);
deba@57
   416
          ++it;
deba@57
   417
        } catch (const ImmediateDetach&) {
deba@57
   418
          (*it)->_index = _observers.end();
deba@57
   419
          (*it)->_notifier = 0;
deba@230
   420
          it = _observers.erase(it);
deba@57
   421
        }
deba@57
   422
      }
deba@57
   423
    }
deba@57
   424
kpeter@314
   425
    // \brief Notifies all the registed observers about the container is
kpeter@314
   426
    // built.
kpeter@314
   427
    //
kpeter@314
   428
    // Notifies all the registed observers about the container is built
kpeter@314
   429
    // from an empty container.
deba@57
   430
    void build() {
deba@57
   431
      typename Observers::reverse_iterator it;
deba@57
   432
      try {
deba@57
   433
        for (it = _observers.rbegin(); it != _observers.rend(); ++it) {
deba@57
   434
          (*it)->build();
deba@57
   435
        }
deba@57
   436
      } catch (...) {
deba@57
   437
        typename Observers::iterator jt;
deba@57
   438
        for (jt = it.base(); jt != _observers.end(); ++jt) {
deba@57
   439
          (*jt)->clear();
deba@57
   440
        }
deba@57
   441
        throw;
deba@57
   442
      }
deba@57
   443
    }
deba@57
   444
kpeter@314
   445
    // \brief Notifies all the registed observers about all items are
kpeter@314
   446
    // erased.
kpeter@314
   447
    //
kpeter@314
   448
    // Notifies all the registed observers about all items are erased
kpeter@314
   449
    // from the container.
deba@57
   450
    void clear() {
deba@57
   451
      typename Observers::iterator it = _observers.begin();
deba@57
   452
      while (it != _observers.end()) {
deba@57
   453
        try {
deba@57
   454
          (*it)->clear();
deba@57
   455
          ++it;
deba@57
   456
        } catch (const ImmediateDetach&) {
deba@57
   457
          (*it)->_index = _observers.end();
deba@57
   458
          (*it)->_notifier = 0;
deba@230
   459
          it = _observers.erase(it);
deba@57
   460
        }
deba@57
   461
      }
deba@57
   462
    }
deba@57
   463
  };
deba@57
   464
deba@57
   465
}
deba@57
   466
deba@57
   467
#endif