lemon/bits/array_map.h
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 936 ddd3c0d3d9bf
parent 617 4137ef9aacc6
child 1092 dceba191c00d
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
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@877
     5
 * Copyright (C) 2003-2010
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_ARRAY_MAP_H
deba@57
    20
#define LEMON_BITS_ARRAY_MAP_H
deba@57
    21
deba@57
    22
#include <memory>
deba@57
    23
deba@57
    24
#include <lemon/bits/traits.h>
deba@57
    25
#include <lemon/bits/alteration_notifier.h>
deba@57
    26
#include <lemon/concept_check.h>
deba@57
    27
#include <lemon/concepts/maps.h>
deba@57
    28
kpeter@314
    29
// \ingroup graphbits
kpeter@314
    30
// \file
kpeter@314
    31
// \brief Graph map based on the array storage.
deba@57
    32
deba@57
    33
namespace lemon {
deba@57
    34
kpeter@314
    35
  // \ingroup graphbits
kpeter@314
    36
  //
kpeter@314
    37
  // \brief Graph map based on the array storage.
kpeter@314
    38
  //
kpeter@361
    39
  // The ArrayMap template class is graph map structure that automatically
kpeter@361
    40
  // updates the map when a key is added to or erased from the graph.
kpeter@361
    41
  // This map uses the allocators to implement the container functionality.
kpeter@314
    42
  //
kpeter@361
    43
  // The template parameters are the Graph, the current Item type and
kpeter@314
    44
  // the Value type of the map.
deba@57
    45
  template <typename _Graph, typename _Item, typename _Value>
alpar@209
    46
  class ArrayMap
deba@57
    47
    : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
deba@57
    48
  public:
kpeter@361
    49
    // The graph type.
kpeter@617
    50
    typedef _Graph GraphType;
kpeter@361
    51
    // The item type.
deba@57
    52
    typedef _Item Item;
kpeter@314
    53
    // The reference map tag.
deba@57
    54
    typedef True ReferenceMapTag;
deba@57
    55
kpeter@361
    56
    // The key type of the map.
deba@57
    57
    typedef _Item Key;
kpeter@314
    58
    // The value type of the map.
deba@57
    59
    typedef _Value Value;
deba@57
    60
kpeter@314
    61
    // The const reference type of the map.
deba@57
    62
    typedef const _Value& ConstReference;
kpeter@314
    63
    // The reference type of the map.
deba@57
    64
    typedef _Value& Reference;
deba@57
    65
kpeter@617
    66
    // The map type.
kpeter@617
    67
    typedef ArrayMap Map;
kpeter@617
    68
kpeter@314
    69
    // The notifier type.
deba@57
    70
    typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
deba@57
    71
kpeter@617
    72
  private:
alpar@877
    73
kpeter@314
    74
    // The MapBase of the Map which imlements the core regisitry function.
deba@57
    75
    typedef typename Notifier::ObserverBase Parent;
alpar@209
    76
deba@57
    77
    typedef std::allocator<Value> Allocator;
deba@57
    78
deba@57
    79
  public:
deba@57
    80
kpeter@314
    81
    // \brief Graph initialized map constructor.
kpeter@314
    82
    //
kpeter@314
    83
    // Graph initialized map constructor.
kpeter@617
    84
    explicit ArrayMap(const GraphType& graph) {
deba@57
    85
      Parent::attach(graph.notifier(Item()));
deba@57
    86
      allocate_memory();
deba@57
    87
      Notifier* nf = Parent::notifier();
deba@57
    88
      Item it;
deba@57
    89
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
    90
        int id = nf->id(it);;
alpar@209
    91
        allocator.construct(&(values[id]), Value());
alpar@209
    92
      }
deba@57
    93
    }
deba@57
    94
kpeter@314
    95
    // \brief Constructor to use default value to initialize the map.
kpeter@314
    96
    //
kpeter@314
    97
    // It constructs a map and initialize all of the the map.
kpeter@617
    98
    ArrayMap(const GraphType& graph, const Value& value) {
deba@57
    99
      Parent::attach(graph.notifier(Item()));
deba@57
   100
      allocate_memory();
deba@57
   101
      Notifier* nf = Parent::notifier();
deba@57
   102
      Item it;
deba@57
   103
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   104
        int id = nf->id(it);;
alpar@209
   105
        allocator.construct(&(values[id]), value);
alpar@209
   106
      }
deba@57
   107
    }
deba@57
   108
kpeter@263
   109
  private:
kpeter@314
   110
    // \brief Constructor to copy a map of the same map type.
kpeter@314
   111
    //
kpeter@314
   112
    // Constructor to copy a map of the same map type.
deba@57
   113
    ArrayMap(const ArrayMap& copy) : Parent() {
deba@57
   114
      if (copy.attached()) {
alpar@209
   115
        attach(*copy.notifier());
deba@57
   116
      }
deba@57
   117
      capacity = copy.capacity;
deba@57
   118
      if (capacity == 0) return;
deba@57
   119
      values = allocator.allocate(capacity);
deba@57
   120
      Notifier* nf = Parent::notifier();
deba@57
   121
      Item it;
deba@57
   122
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   123
        int id = nf->id(it);;
alpar@209
   124
        allocator.construct(&(values[id]), copy.values[id]);
deba@57
   125
      }
deba@57
   126
    }
deba@57
   127
kpeter@314
   128
    // \brief Assign operator.
kpeter@314
   129
    //
kpeter@314
   130
    // This operator assigns for each item in the map the
kpeter@314
   131
    // value mapped to the same item in the copied map.
kpeter@314
   132
    // The parameter map should be indiced with the same
kpeter@314
   133
    // itemset because this assign operator does not change
kpeter@314
   134
    // the container of the map.
deba@57
   135
    ArrayMap& operator=(const ArrayMap& cmap) {
deba@57
   136
      return operator=<ArrayMap>(cmap);
deba@57
   137
    }
deba@57
   138
deba@57
   139
kpeter@314
   140
    // \brief Template assign operator.
kpeter@314
   141
    //
kpeter@503
   142
    // The given parameter should conform to the ReadMap
kpeter@314
   143
    // concecpt and could be indiced by the current item set of
kpeter@314
   144
    // the NodeMap. In this case the value for each item
kpeter@314
   145
    // is assigned by the value of the given ReadMap.
deba@57
   146
    template <typename CMap>
deba@57
   147
    ArrayMap& operator=(const CMap& cmap) {
deba@57
   148
      checkConcept<concepts::ReadMap<Key, _Value>, CMap>();
deba@57
   149
      const typename Parent::Notifier* nf = Parent::notifier();
deba@57
   150
      Item it;
deba@57
   151
      for (nf->first(it); it != INVALID; nf->next(it)) {
deba@57
   152
        set(it, cmap[it]);
deba@57
   153
      }
deba@57
   154
      return *this;
deba@57
   155
    }
deba@57
   156
kpeter@263
   157
  public:
kpeter@314
   158
    // \brief The destructor of the map.
kpeter@314
   159
    //
kpeter@314
   160
    // The destructor of the map.
alpar@209
   161
    virtual ~ArrayMap() {
deba@57
   162
      if (attached()) {
alpar@209
   163
        clear();
alpar@209
   164
        detach();
deba@57
   165
      }
deba@57
   166
    }
alpar@209
   167
deba@57
   168
  protected:
deba@57
   169
deba@57
   170
    using Parent::attach;
deba@57
   171
    using Parent::detach;
deba@57
   172
    using Parent::attached;
deba@57
   173
deba@57
   174
  public:
deba@57
   175
kpeter@314
   176
    // \brief The subscript operator.
kpeter@314
   177
    //
kpeter@314
   178
    // The subscript operator. The map can be subscripted by the
kpeter@314
   179
    // actual keys of the graph.
deba@57
   180
    Value& operator[](const Key& key) {
deba@57
   181
      int id = Parent::notifier()->id(key);
deba@57
   182
      return values[id];
alpar@209
   183
    }
alpar@209
   184
kpeter@314
   185
    // \brief The const subscript operator.
kpeter@314
   186
    //
kpeter@314
   187
    // The const subscript operator. The map can be subscripted by the
kpeter@314
   188
    // actual keys of the graph.
deba@57
   189
    const Value& operator[](const Key& key) const {
deba@57
   190
      int id = Parent::notifier()->id(key);
deba@57
   191
      return values[id];
deba@57
   192
    }
deba@57
   193
kpeter@314
   194
    // \brief Setter function of the map.
kpeter@314
   195
    //
kpeter@314
   196
    // Setter function of the map. Equivalent with map[key] = val.
kpeter@314
   197
    // This is a compatibility feature with the not dereferable maps.
deba@57
   198
    void set(const Key& key, const Value& val) {
deba@57
   199
      (*this)[key] = val;
deba@57
   200
    }
deba@57
   201
deba@57
   202
  protected:
deba@57
   203
kpeter@314
   204
    // \brief Adds a new key to the map.
kpeter@314
   205
    //
kpeter@361
   206
    // It adds a new key to the map. It is called by the observer notifier
kpeter@314
   207
    // and it overrides the add() member function of the observer base.
deba@57
   208
    virtual void add(const Key& key) {
deba@57
   209
      Notifier* nf = Parent::notifier();
deba@57
   210
      int id = nf->id(key);
deba@57
   211
      if (id >= capacity) {
alpar@209
   212
        int new_capacity = (capacity == 0 ? 1 : capacity);
alpar@209
   213
        while (new_capacity <= id) {
alpar@209
   214
          new_capacity <<= 1;
alpar@209
   215
        }
alpar@209
   216
        Value* new_values = allocator.allocate(new_capacity);
alpar@209
   217
        Item it;
alpar@209
   218
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   219
          int jd = nf->id(it);;
alpar@209
   220
          if (id != jd) {
alpar@209
   221
            allocator.construct(&(new_values[jd]), values[jd]);
alpar@209
   222
            allocator.destroy(&(values[jd]));
alpar@209
   223
          }
alpar@209
   224
        }
alpar@209
   225
        if (capacity != 0) allocator.deallocate(values, capacity);
alpar@209
   226
        values = new_values;
alpar@209
   227
        capacity = new_capacity;
deba@57
   228
      }
deba@57
   229
      allocator.construct(&(values[id]), Value());
deba@57
   230
    }
deba@57
   231
kpeter@314
   232
    // \brief Adds more new keys to the map.
kpeter@314
   233
    //
kpeter@361
   234
    // It adds more new keys to the map. It is called by the observer notifier
kpeter@314
   235
    // and it overrides the add() member function of the observer base.
deba@57
   236
    virtual void add(const std::vector<Key>& keys) {
deba@57
   237
      Notifier* nf = Parent::notifier();
deba@57
   238
      int max_id = -1;
deba@57
   239
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   240
        int id = nf->id(keys[i]);
alpar@209
   241
        if (id > max_id) {
alpar@209
   242
          max_id = id;
alpar@209
   243
        }
deba@57
   244
      }
deba@57
   245
      if (max_id >= capacity) {
alpar@209
   246
        int new_capacity = (capacity == 0 ? 1 : capacity);
alpar@209
   247
        while (new_capacity <= max_id) {
alpar@209
   248
          new_capacity <<= 1;
alpar@209
   249
        }
alpar@209
   250
        Value* new_values = allocator.allocate(new_capacity);
alpar@209
   251
        Item it;
alpar@209
   252
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   253
          int id = nf->id(it);
alpar@209
   254
          bool found = false;
alpar@209
   255
          for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   256
            int jd = nf->id(keys[i]);
alpar@209
   257
            if (id == jd) {
alpar@209
   258
              found = true;
alpar@209
   259
              break;
alpar@209
   260
            }
alpar@209
   261
          }
alpar@209
   262
          if (found) continue;
alpar@209
   263
          allocator.construct(&(new_values[id]), values[id]);
alpar@209
   264
          allocator.destroy(&(values[id]));
alpar@209
   265
        }
alpar@209
   266
        if (capacity != 0) allocator.deallocate(values, capacity);
alpar@209
   267
        values = new_values;
alpar@209
   268
        capacity = new_capacity;
deba@57
   269
      }
deba@57
   270
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   271
        int id = nf->id(keys[i]);
alpar@209
   272
        allocator.construct(&(values[id]), Value());
deba@57
   273
      }
deba@57
   274
    }
alpar@209
   275
kpeter@314
   276
    // \brief Erase a key from the map.
kpeter@314
   277
    //
kpeter@361
   278
    // Erase a key from the map. It is called by the observer notifier
kpeter@314
   279
    // and it overrides the erase() member function of the observer base.
deba@57
   280
    virtual void erase(const Key& key) {
deba@57
   281
      int id = Parent::notifier()->id(key);
deba@57
   282
      allocator.destroy(&(values[id]));
deba@57
   283
    }
deba@57
   284
kpeter@314
   285
    // \brief Erase more keys from the map.
kpeter@314
   286
    //
kpeter@361
   287
    // Erase more keys from the map. It is called by the observer notifier
kpeter@314
   288
    // and it overrides the erase() member function of the observer base.
deba@57
   289
    virtual void erase(const std::vector<Key>& keys) {
deba@57
   290
      for (int i = 0; i < int(keys.size()); ++i) {
alpar@209
   291
        int id = Parent::notifier()->id(keys[i]);
alpar@209
   292
        allocator.destroy(&(values[id]));
deba@57
   293
      }
deba@57
   294
    }
deba@57
   295
kpeter@361
   296
    // \brief Builds the map.
kpeter@314
   297
    //
kpeter@361
   298
    // It builds the map. It is called by the observer notifier
kpeter@314
   299
    // and it overrides the build() member function of the observer base.
deba@57
   300
    virtual void build() {
deba@57
   301
      Notifier* nf = Parent::notifier();
deba@57
   302
      allocate_memory();
deba@57
   303
      Item it;
deba@57
   304
      for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   305
        int id = nf->id(it);;
alpar@209
   306
        allocator.construct(&(values[id]), Value());
alpar@209
   307
      }
deba@57
   308
    }
deba@57
   309
kpeter@314
   310
    // \brief Clear the map.
kpeter@314
   311
    //
kpeter@361
   312
    // It erase all items from the map. It is called by the observer notifier
kpeter@314
   313
    // and it overrides the clear() member function of the observer base.
alpar@209
   314
    virtual void clear() {
deba@57
   315
      Notifier* nf = Parent::notifier();
deba@57
   316
      if (capacity != 0) {
alpar@209
   317
        Item it;
alpar@209
   318
        for (nf->first(it); it != INVALID; nf->next(it)) {
alpar@209
   319
          int id = nf->id(it);
alpar@209
   320
          allocator.destroy(&(values[id]));
alpar@209
   321
        }
alpar@209
   322
        allocator.deallocate(values, capacity);
alpar@209
   323
        capacity = 0;
deba@57
   324
      }
deba@57
   325
    }
deba@57
   326
deba@57
   327
  private:
alpar@209
   328
deba@57
   329
    void allocate_memory() {
deba@57
   330
      int max_id = Parent::notifier()->maxId();
deba@57
   331
      if (max_id == -1) {
alpar@209
   332
        capacity = 0;
alpar@209
   333
        values = 0;
alpar@209
   334
        return;
deba@57
   335
      }
deba@57
   336
      capacity = 1;
deba@57
   337
      while (capacity <= max_id) {
alpar@209
   338
        capacity <<= 1;
deba@57
   339
      }
alpar@209
   340
      values = allocator.allocate(capacity);
alpar@209
   341
    }
deba@57
   342
deba@57
   343
    int capacity;
deba@57
   344
    Value* values;
deba@57
   345
    Allocator allocator;
deba@57
   346
alpar@209
   347
  };
deba@57
   348
deba@57
   349
}
deba@57
   350
alpar@209
   351
#endif