lemon/dimacs.h
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 08 Sep 2017 17:04:30 +0200
changeset 1159 332627dd249e
parent 1158 f37f0845cf32
child 1160 bc571f16e1e9
permissions -rw-r--r--
Fixes in API doc of DIMACS reader methods
alpar@385
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
alpar@385
     2
 *
alpar@385
     3
 * This file is a part of LEMON, a generic C++ optimization library.
alpar@385
     4
 *
alpar@440
     5
 * Copyright (C) 2003-2009
alpar@385
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@385
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@385
     8
 *
alpar@385
     9
 * Permission to use, modify and distribute this software is granted
alpar@385
    10
 * provided that this copyright notice appears in all copies. For
alpar@385
    11
 * precise terms see the accompanying LICENSE file.
alpar@385
    12
 *
alpar@385
    13
 * This software is provided "AS IS" with no warranty of any kind,
alpar@385
    14
 * express or implied, and with no claim as to its suitability for any
alpar@385
    15
 * purpose.
alpar@385
    16
 *
alpar@385
    17
 */
alpar@385
    18
alpar@385
    19
#ifndef LEMON_DIMACS_H
alpar@385
    20
#define LEMON_DIMACS_H
alpar@385
    21
alpar@385
    22
#include <iostream>
alpar@385
    23
#include <string>
alpar@385
    24
#include <vector>
alpar@561
    25
#include <limits>
alpar@385
    26
#include <lemon/maps.h>
alpar@387
    27
#include <lemon/error.h>
kpeter@1159
    28
alpar@385
    29
/// \ingroup dimacs_group
alpar@385
    30
/// \file
alpar@385
    31
/// \brief DIMACS file format reader.
alpar@385
    32
alpar@385
    33
namespace lemon {
alpar@385
    34
alpar@385
    35
  /// \addtogroup dimacs_group
alpar@385
    36
  /// @{
alpar@385
    37
alpar@387
    38
  /// DIMACS file type descriptor.
alpar@387
    39
  struct DimacsDescriptor
alpar@387
    40
  {
alpar@387
    41
    ///File type enum
alpar@387
    42
    enum Type
alpar@387
    43
      {
alpar@387
    44
        NONE, MIN, MAX, SP, MAT
alpar@387
    45
      };
alpar@387
    46
    ///The file type
alpar@387
    47
    Type type;
kpeter@388
    48
    ///The number of nodes in the graph
alpar@387
    49
    int nodeNum;
kpeter@388
    50
    ///The number of edges in the graph
alpar@387
    51
    int edgeNum;
alpar@387
    52
    int lineShift;
alpar@387
    53
    /// Constructor. Sets the type to NONE.
alpar@387
    54
    DimacsDescriptor() : type(NONE) {}
alpar@387
    55
  };
alpar@387
    56
alpar@387
    57
  ///Discover the type of a DIMACS file
alpar@387
    58
alpar@561
    59
  ///It starts seeking the beginning of the file for the problem type
kpeter@388
    60
  ///and size info. The found data is returned in a special struct
alpar@387
    61
  ///that can be evaluated and passed to the appropriate reader
alpar@387
    62
  ///function.
alpar@387
    63
  DimacsDescriptor dimacsType(std::istream& is)
alpar@387
    64
  {
alpar@387
    65
    DimacsDescriptor r;
alpar@387
    66
    std::string problem,str;
alpar@387
    67
    char c;
alpar@387
    68
    r.lineShift=0;
alpar@387
    69
    while (is >> c)
alpar@387
    70
      switch(c)
alpar@387
    71
        {
alpar@387
    72
        case 'p':
alpar@387
    73
          if(is >> problem >> r.nodeNum >> r.edgeNum)
alpar@387
    74
            {
alpar@387
    75
              getline(is, str);
alpar@387
    76
              r.lineShift++;
alpar@387
    77
              if(problem=="min") r.type=DimacsDescriptor::MIN;
alpar@387
    78
              else if(problem=="max") r.type=DimacsDescriptor::MAX;
alpar@387
    79
              else if(problem=="sp") r.type=DimacsDescriptor::SP;
alpar@387
    80
              else if(problem=="mat") r.type=DimacsDescriptor::MAT;
alpar@387
    81
              else throw FormatError("Unknown problem type");
alpar@387
    82
              return r;
alpar@387
    83
            }
alpar@387
    84
          else
alpar@387
    85
            {
alpar@387
    86
              throw FormatError("Missing or wrong problem type declaration.");
alpar@387
    87
            }
alpar@387
    88
          break;
alpar@387
    89
        case 'c':
alpar@387
    90
          getline(is, str);
alpar@387
    91
          r.lineShift++;
alpar@387
    92
          break;
alpar@387
    93
        default:
alpar@387
    94
          throw FormatError("Unknown DIMACS declaration.");
alpar@387
    95
        }
alpar@387
    96
    throw FormatError("Missing problem type declaration.");
alpar@387
    97
  }
alpar@387
    98
alpar@387
    99
alpar@387
   100
kpeter@388
   101
  /// DIMACS minimum cost flow reader function.
alpar@385
   102
  ///
kpeter@388
   103
  /// This function reads a minimum cost flow instance from DIMACS format,
kpeter@388
   104
  /// i.e. from a DIMACS file having a line starting with
alpar@385
   105
  /// \code
alpar@385
   106
  ///   p min
alpar@385
   107
  /// \endcode
alpar@387
   108
  /// At the beginning, \c g is cleared by \c g.clear(). The supply
alpar@561
   109
  /// amount of the nodes are written to the \c supply node map
alpar@561
   110
  /// (they are signed values). The lower bounds, capacities and costs
alpar@561
   111
  /// of the arcs are written to the \c lower, \c capacity and \c cost
alpar@561
   112
  /// arc maps.
alpar@561
   113
  ///
alpar@561
   114
  /// If the capacity of an arc is less than the lower bound, it will
alpar@561
   115
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@561
   116
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@561
   117
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@561
   118
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@561
   119
  /// a non-zero value, that value will be used as "infinite".
alpar@387
   120
  ///
alpar@387
   121
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1159
   122
  /// the descriptor struct should be given by the \c desc parameter.
alpar@385
   123
  template <typename Digraph, typename LowerMap,
alpar@387
   124
            typename CapacityMap, typename CostMap,
alpar@387
   125
            typename SupplyMap>
alpar@387
   126
  void readDimacsMin(std::istream& is,
alpar@387
   127
                     Digraph &g,
alpar@387
   128
                     LowerMap& lower,
alpar@387
   129
                     CapacityMap& capacity,
alpar@387
   130
                     CostMap& cost,
alpar@387
   131
                     SupplyMap& supply,
alpar@561
   132
                     typename CapacityMap::Value infty = 0,
alpar@387
   133
                     DimacsDescriptor desc=DimacsDescriptor())
alpar@385
   134
  {
alpar@385
   135
    g.clear();
alpar@385
   136
    std::vector<typename Digraph::Node> nodes;
alpar@385
   137
    typename Digraph::Arc e;
alpar@385
   138
    std::string problem, str;
alpar@385
   139
    char c;
alpar@385
   140
    int i, j;
alpar@387
   141
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@387
   142
    if(desc.type!=DimacsDescriptor::MIN)
alpar@387
   143
      throw FormatError("Problem type mismatch");
alpar@387
   144
alpar@387
   145
    nodes.resize(desc.nodeNum + 1);
alpar@387
   146
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@387
   147
      nodes[k] = g.addNode();
alpar@387
   148
      supply.set(nodes[k], 0);
alpar@387
   149
    }
alpar@387
   150
alpar@385
   151
    typename SupplyMap::Value sup;
alpar@385
   152
    typename CapacityMap::Value low;
alpar@385
   153
    typename CapacityMap::Value cap;
alpar@385
   154
    typename CostMap::Value co;
alpar@561
   155
    typedef typename CapacityMap::Value Capacity;
alpar@561
   156
    if(infty==0)
alpar@561
   157
      infty = std::numeric_limits<Capacity>::has_infinity ?
alpar@561
   158
        std::numeric_limits<Capacity>::infinity() :
alpar@561
   159
        std::numeric_limits<Capacity>::max();
alpar@561
   160
alpar@385
   161
    while (is >> c) {
alpar@385
   162
      switch (c) {
alpar@385
   163
      case 'c': // comment line
alpar@385
   164
        getline(is, str);
alpar@385
   165
        break;
alpar@385
   166
      case 'n': // node definition line
alpar@385
   167
        is >> i >> sup;
alpar@385
   168
        getline(is, str);
alpar@385
   169
        supply.set(nodes[i], sup);
alpar@385
   170
        break;
alpar@561
   171
      case 'a': // arc definition line
alpar@385
   172
        is >> i >> j >> low >> cap >> co;
alpar@385
   173
        getline(is, str);
alpar@385
   174
        e = g.addArc(nodes[i], nodes[j]);
alpar@385
   175
        lower.set(e, low);
alpar@561
   176
        if (cap >= low)
alpar@385
   177
          capacity.set(e, cap);
alpar@385
   178
        else
alpar@561
   179
          capacity.set(e, infty);
alpar@385
   180
        cost.set(e, co);
alpar@385
   181
        break;
alpar@385
   182
      }
alpar@385
   183
    }
alpar@385
   184
  }
alpar@385
   185
alpar@385
   186
  template<typename Digraph, typename CapacityMap>
alpar@387
   187
  void _readDimacs(std::istream& is,
alpar@387
   188
                   Digraph &g,
alpar@387
   189
                   CapacityMap& capacity,
alpar@387
   190
                   typename Digraph::Node &s,
alpar@387
   191
                   typename Digraph::Node &t,
alpar@561
   192
                   typename CapacityMap::Value infty = 0,
alpar@387
   193
                   DimacsDescriptor desc=DimacsDescriptor()) {
alpar@385
   194
    g.clear();
alpar@387
   195
    s=t=INVALID;
alpar@385
   196
    std::vector<typename Digraph::Node> nodes;
alpar@385
   197
    typename Digraph::Arc e;
alpar@385
   198
    char c, d;
alpar@385
   199
    int i, j;
alpar@385
   200
    typename CapacityMap::Value _cap;
alpar@385
   201
    std::string str;
alpar@387
   202
    nodes.resize(desc.nodeNum + 1);
alpar@387
   203
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@387
   204
      nodes[k] = g.addNode();
alpar@387
   205
    }
alpar@561
   206
    typedef typename CapacityMap::Value Capacity;
alpar@387
   207
alpar@561
   208
    if(infty==0)
alpar@561
   209
      infty = std::numeric_limits<Capacity>::has_infinity ?
alpar@561
   210
        std::numeric_limits<Capacity>::infinity() :
alpar@561
   211
        std::numeric_limits<Capacity>::max();
alpar@561
   212
 
alpar@385
   213
    while (is >> c) {
alpar@385
   214
      switch (c) {
alpar@385
   215
      case 'c': // comment line
alpar@385
   216
        getline(is, str);
alpar@385
   217
        break;
alpar@385
   218
      case 'n': // node definition line
alpar@387
   219
        if (desc.type==DimacsDescriptor::SP) { // shortest path problem
alpar@385
   220
          is >> i;
alpar@385
   221
          getline(is, str);
alpar@385
   222
          s = nodes[i];
alpar@385
   223
        }
alpar@387
   224
        if (desc.type==DimacsDescriptor::MAX) { // max flow problem
alpar@385
   225
          is >> i >> d;
alpar@385
   226
          getline(is, str);
alpar@385
   227
          if (d == 's') s = nodes[i];
alpar@385
   228
          if (d == 't') t = nodes[i];
alpar@385
   229
        }
alpar@385
   230
        break;
alpar@561
   231
      case 'a': // arc definition line
alpar@561
   232
        if (desc.type==DimacsDescriptor::SP) {
alpar@385
   233
          is >> i >> j >> _cap;
alpar@385
   234
          getline(is, str);
alpar@385
   235
          e = g.addArc(nodes[i], nodes[j]);
alpar@385
   236
          capacity.set(e, _cap);
alpar@561
   237
        } 
alpar@561
   238
        else if (desc.type==DimacsDescriptor::MAX) {
alpar@561
   239
          is >> i >> j >> _cap;
alpar@561
   240
          getline(is, str);
alpar@561
   241
          e = g.addArc(nodes[i], nodes[j]);
alpar@561
   242
          if (_cap >= 0)
alpar@561
   243
            capacity.set(e, _cap);
alpar@561
   244
          else
alpar@561
   245
            capacity.set(e, infty);
alpar@561
   246
        }
alpar@561
   247
        else {
alpar@385
   248
          is >> i >> j;
alpar@385
   249
          getline(is, str);
alpar@385
   250
          g.addArc(nodes[i], nodes[j]);
alpar@385
   251
        }
alpar@385
   252
        break;
alpar@385
   253
      }
alpar@385
   254
    }
alpar@385
   255
  }
alpar@385
   256
kpeter@388
   257
  /// DIMACS maximum flow reader function.
alpar@387
   258
  ///
kpeter@388
   259
  /// This function reads a maximum flow instance from DIMACS format,
kpeter@388
   260
  /// i.e. from a DIMACS file having a line starting with
alpar@387
   261
  /// \code
alpar@387
   262
  ///   p max
alpar@387
   263
  /// \endcode
alpar@387
   264
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@561
   265
  /// capacities are written to the \c capacity arc map and \c s and
alpar@561
   266
  /// \c t are set to the source and the target nodes.
alpar@561
   267
  ///
alpar@561
   268
  /// If the capacity of an arc is negative, it will
alpar@561
   269
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@561
   270
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@561
   271
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@561
   272
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@561
   273
  /// a non-zero value, that value will be used as "infinite".
alpar@387
   274
  ///
alpar@387
   275
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1159
   276
  /// the descriptor struct should be given by the \c desc parameter.
alpar@387
   277
  template<typename Digraph, typename CapacityMap>
alpar@387
   278
  void readDimacsMax(std::istream& is,
alpar@387
   279
                     Digraph &g,
alpar@387
   280
                     CapacityMap& capacity,
alpar@387
   281
                     typename Digraph::Node &s,
alpar@387
   282
                     typename Digraph::Node &t,
alpar@561
   283
                     typename CapacityMap::Value infty = 0,
alpar@387
   284
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@387
   285
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@387
   286
    if(desc.type!=DimacsDescriptor::MAX)
alpar@387
   287
      throw FormatError("Problem type mismatch");
alpar@561
   288
    _readDimacs(is,g,capacity,s,t,infty,desc);
alpar@387
   289
  }
alpar@387
   290
alpar@385
   291
  /// DIMACS shortest path reader function.
alpar@385
   292
  ///
alpar@385
   293
  /// This function reads a shortest path instance from DIMACS format,
kpeter@388
   294
  /// i.e. from a DIMACS file having a line starting with
alpar@385
   295
  /// \code
alpar@385
   296
  ///   p sp
alpar@385
   297
  /// \endcode
alpar@387
   298
  /// At the beginning, \c g is cleared by \c g.clear(). The arc
alpar@561
   299
  /// lengths are written to the \c length arc map and \c s is set to the
alpar@385
   300
  /// source node.
alpar@387
   301
  ///
alpar@387
   302
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1159
   303
  /// the descriptor struct should be given by the \c desc parameter.
alpar@387
   304
  template<typename Digraph, typename LengthMap>
alpar@387
   305
  void readDimacsSp(std::istream& is,
alpar@387
   306
                    Digraph &g,
alpar@387
   307
                    LengthMap& length,
alpar@387
   308
                    typename Digraph::Node &s,
alpar@387
   309
                    DimacsDescriptor desc=DimacsDescriptor()) {
alpar@386
   310
    typename Digraph::Node t;
alpar@387
   311
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@387
   312
    if(desc.type!=DimacsDescriptor::SP)
alpar@387
   313
      throw FormatError("Problem type mismatch");
alpar@561
   314
    _readDimacs(is, g, length, s, t, 0, desc);
alpar@385
   315
  }
alpar@385
   316
alpar@385
   317
  /// DIMACS capacitated digraph reader function.
alpar@385
   318
  ///
alpar@385
   319
  /// This function reads an arc capacitated digraph instance from
alpar@561
   320
  /// DIMACS 'max' or 'sp' format.
alpar@387
   321
  /// At the beginning, \c g is cleared by \c g.clear()
alpar@561
   322
  /// and the arc capacities/lengths are written to the \c capacity
alpar@561
   323
  /// arc map.
alpar@561
   324
  ///
alpar@561
   325
  /// In case of the 'max' format, if the capacity of an arc is negative,
alpar@561
   326
  /// it will
alpar@561
   327
  /// be set to "infinite" instead. The actual value of "infinite" is
alpar@561
   328
  /// contolled by the \c infty parameter. If it is 0 (the default value),
alpar@561
   329
  /// \c std::numeric_limits<Capacity>::infinity() will be used if available,
alpar@561
   330
  /// \c std::numeric_limits<Capacity>::max() otherwise. If \c infty is set to
alpar@561
   331
  /// a non-zero value, that value will be used as "infinite".
alpar@387
   332
  ///
alpar@387
   333
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1159
   334
  /// the descriptor struct should be given by the \c desc parameter.
alpar@385
   335
  template<typename Digraph, typename CapacityMap>
alpar@387
   336
  void readDimacsCap(std::istream& is,
alpar@387
   337
                     Digraph &g,
alpar@387
   338
                     CapacityMap& capacity,
alpar@561
   339
                     typename CapacityMap::Value infty = 0,
alpar@387
   340
                     DimacsDescriptor desc=DimacsDescriptor()) {
alpar@386
   341
    typename Digraph::Node u,v;
alpar@387
   342
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
kpeter@1158
   343
    if(desc.type!=DimacsDescriptor::MAX && desc.type!=DimacsDescriptor::SP)
alpar@387
   344
      throw FormatError("Problem type mismatch");
alpar@561
   345
    _readDimacs(is, g, capacity, u, v, infty, desc);
alpar@385
   346
  }
alpar@385
   347
alpar@525
   348
  template<typename Graph>
alpar@525
   349
  typename enable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
alpar@525
   350
  _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
alpar@525
   351
              dummy<0> = 0)
alpar@525
   352
  {
alpar@525
   353
    g.addEdge(s,t);
alpar@525
   354
  }
alpar@525
   355
  template<typename Graph>
alpar@525
   356
  typename disable_if<lemon::UndirectedTagIndicator<Graph>,void>::type
alpar@525
   357
  _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t,
alpar@525
   358
              dummy<1> = 1)
alpar@525
   359
  {
alpar@525
   360
    g.addArc(s,t);
alpar@525
   361
  }
alpar@525
   362
  
alpar@525
   363
  /// DIMACS plain (di)graph reader function.
alpar@385
   364
  ///
alpar@525
   365
  /// This function reads a (di)graph without any designated nodes and
alpar@385
   366
  /// maps from DIMACS format, i.e. from DIMACS files having a line
alpar@385
   367
  /// starting with
alpar@385
   368
  /// \code
alpar@385
   369
  ///   p mat
alpar@385
   370
  /// \endcode
alpar@387
   371
  /// At the beginning, \c g is cleared by \c g.clear().
alpar@387
   372
  ///
alpar@387
   373
  /// If the file type was previously evaluated by dimacsType(), then
kpeter@1159
   374
  /// the descriptor struct should be given by the \c desc parameter.
alpar@525
   375
  template<typename Graph>
alpar@525
   376
  void readDimacsMat(std::istream& is, Graph &g,
alpar@525
   377
                     DimacsDescriptor desc=DimacsDescriptor())
alpar@525
   378
  {
alpar@387
   379
    if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is);
alpar@387
   380
    if(desc.type!=DimacsDescriptor::MAT)
alpar@387
   381
      throw FormatError("Problem type mismatch");
alpar@525
   382
alpar@525
   383
    g.clear();
alpar@525
   384
    std::vector<typename Graph::Node> nodes;
alpar@525
   385
    char c;
alpar@525
   386
    int i, j;
alpar@525
   387
    std::string str;
alpar@525
   388
    nodes.resize(desc.nodeNum + 1);
alpar@525
   389
    for (int k = 1; k <= desc.nodeNum; ++k) {
alpar@525
   390
      nodes[k] = g.addNode();
alpar@525
   391
    }
alpar@525
   392
    
alpar@525
   393
    while (is >> c) {
alpar@525
   394
      switch (c) {
alpar@525
   395
      case 'c': // comment line
alpar@525
   396
        getline(is, str);
alpar@525
   397
        break;
alpar@525
   398
      case 'n': // node definition line
alpar@525
   399
        break;
alpar@561
   400
      case 'a': // arc definition line
alpar@525
   401
        is >> i >> j;
alpar@525
   402
        getline(is, str);
alpar@525
   403
        _addArcEdge(g,nodes[i], nodes[j]);
alpar@525
   404
        break;
alpar@525
   405
      }
alpar@525
   406
    }
alpar@385
   407
  }
alpar@385
   408
alpar@385
   409
  /// DIMACS plain digraph writer function.
alpar@385
   410
  ///
alpar@385
   411
  /// This function writes a digraph without any designated nodes and
alpar@385
   412
  /// maps into DIMACS format, i.e. into DIMACS file having a line
alpar@385
   413
  /// starting with
alpar@385
   414
  /// \code
alpar@385
   415
  ///   p mat
alpar@385
   416
  /// \endcode
alpar@387
   417
  /// If \c comment is not empty, then it will be printed in the first line
alpar@387
   418
  /// prefixed by 'c'.
alpar@385
   419
  template<typename Digraph>
alpar@387
   420
  void writeDimacsMat(std::ostream& os, const Digraph &g,
alpar@387
   421
                      std::string comment="") {
alpar@385
   422
    typedef typename Digraph::NodeIt NodeIt;
alpar@385
   423
    typedef typename Digraph::ArcIt ArcIt;
alpar@385
   424
alpar@440
   425
    if(!comment.empty())
alpar@387
   426
      os << "c " << comment << std::endl;
alpar@385
   427
    os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl;
alpar@385
   428
alpar@385
   429
    typename Digraph::template NodeMap<int> nodes(g);
alpar@385
   430
    int i = 1;
alpar@385
   431
    for(NodeIt v(g); v != INVALID; ++v) {
alpar@385
   432
      nodes.set(v, i);
alpar@385
   433
      ++i;
alpar@385
   434
    }
alpar@385
   435
    for(ArcIt e(g); e != INVALID; ++e) {
alpar@385
   436
      os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)]
alpar@385
   437
         << std::endl;
alpar@385
   438
    }
alpar@385
   439
  }
alpar@385
   440
alpar@385
   441
  /// @}
alpar@385
   442
alpar@385
   443
} //namespace lemon
alpar@385
   444
alpar@385
   445
#endif //LEMON_DIMACS_H