diff --git a/README.md b/README.md index e9580bc4..8416959d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ * New YASK users may want to start with the [YASK tutorial](http://intel.github.io/yask/YASK-tutorial.pdf). * Users with existing YASK-based code may want to jump to the [backward-compatibility notices](#backward-compatibility-notices). +* All YASK users will also be interested in the [API documentation](http://intel.github.io/yask/api/html/index.html). ## Overview YASK is a framework to rapidly create high-performance stencil code including optimizations and features such as @@ -11,7 +12,7 @@ YASK is a framework to rapidly create high-performance stencil code including op * Scaling to multiple sockets and nodes via MPI with overlapped communication and compute. * Spatial tiling with automatically-tuned block sizes. * Temporal tiling in multiple dimensions to further increase cache locality. -* APIs for C++ and Python: [API documentation](http://intel.github.io/yask/api/html/index.html) +* APIs for C++ and Python. YASK contains a domain-specific compiler to convert stencil-equation specifications to SIMD-optimized code for Intel(R) Xeon Phi(TM) and Intel(R) Xeon(R) processors. diff --git a/src/common/common_utils.cpp b/src/common/common_utils.cpp index 0767a9e5..712669ca 100644 --- a/src/common/common_utils.cpp +++ b/src/common/common_utils.cpp @@ -43,7 +43,7 @@ namespace yask { // for numbers above 9 (at least up to 99). // Format: "major.minor.patch". - const string version = "3.01.00"; + const string version = "3.01.01"; string yask_get_version_string() { return version; diff --git a/src/common/common_utils.hpp b/src/common/common_utils.hpp index b096c363..6b59954b 100644 --- a/src/common/common_utils.hpp +++ b/src/common/common_utils.hpp @@ -179,51 +179,92 @@ namespace yask { // Set that retains order of things added. // Or, vector that allows insertion if element doesn't exist. - // TODO: hide vector inside class and provide proper accessor methods. template - class vector_set : public std::vector { - std::map _posn; - - private: - virtual void push_front(const T& val) { - THROW_YASK_EXCEPTION("push_front() not allowed"); - } + class vector_set final { + std::vector _items; // no duplicates. + std::map _posn; // _posn[_items[i]] = i; public: vector_set() {} - virtual ~vector_set() {} + ~vector_set() {} - // Copy ctor. - vector_set(const vector_set& src) : - std::vector(src), _posn(src._posn) {} + // Default assign and copy ctor are okay. - virtual size_t count(const T& val) const { + // STL methods. + // Do not provide any non-const iterators or element access to prevent + // breaking _items <-> _posn relationship. + typename std::vector::const_iterator begin() const { + return _items.begin(); + } + typename std::vector::const_iterator end() const { + return _items.end(); + } + const T& at(size_t i) const { + return _items.at(i); + } + const T& operator[](size_t i) const { + return _items[i]; + } + const T& front() const { + return _items.front(); + } + const T& back() const { + return _items.back(); + } + size_t size() const { + assert(_items.size() == _posn.size()); + return _items.size(); + } + bool empty() const { + return size() == 0 ; + } + size_t count(const T& val) const { + assert(_items.size() == _posn.size()); return _posn.count(val); } - virtual void insert(const T& val) { + void insert(const T& val) { + assert(_items.size() == _posn.size()); if (_posn.count(val) == 0) { - std::vector::push_back(val); - _posn[val] = std::vector::size() - 1; + _items.push_back(val); + _posn[val] = _items.size() - 1; } + assert(_items.size() == _posn.size()); } - virtual void push_back(const T& val) { - insert(val); + void push_back(const T& val) { + insert(val); // Does nothing if already exists. } - virtual void erase(const T& val) { + void erase(const T& val) { if (_posn.count(val) > 0) { size_t op = _posn.at(val); - std::vector::erase(std::vector::begin() + op); + _items.erase(_items.begin() + op); + + // Repair positions of items after 'val'. for (auto pi : _posn) { auto& p = pi.second; if (p > op) p--; } + _posn.erase(val); } + assert(_items.size() == _posn.size()); } - virtual void clear() { - std::vector::clear(); + void clear() { + _items.clear(); _posn.clear(); } + + // New methods. + void swap(size_t i, size_t j) { + assert(i < _items.size()); + assert(j < _items.size()); + if (i == j) + return; + T tmp = _items[i]; + _items[i] = _items[j]; + _items[j] = tmp; + _posn[_items[i]] = i; + _posn[_items[j]] = j; + } }; } // namespace. diff --git a/src/common/tuple.hpp b/src/common/tuple.hpp index 72e386a6..9d6547b2 100644 --- a/src/common/tuple.hpp +++ b/src/common/tuple.hpp @@ -125,6 +125,9 @@ namespace yask { void setVal(const T& val) { _val = val; } // Comparison ops. + // Compare name pointers and actual names in case there + // is more than one pool, which can happen when loading + // more than one dynamic lib. bool operator==(const Scalar& rhs) const { return _val == rhs._val && (_namep == rhs._namep || *_namep == *rhs._namep); @@ -133,7 +136,7 @@ namespace yask { return (_val < rhs._val) ? true : (_val > rhs._val) ? false : (_namep == rhs._namep) ? false : - (*_namep < *rhs._namep) ? true : false; + (*_namep < *rhs._namep); } }; @@ -183,6 +186,12 @@ namespace yask { const std::vector>& getDims() const { return _q; } + typename std::vector>::const_iterator begin() const { + return _q.begin(); + } + typename std::vector>::const_iterator end() const { + return _q.end(); + } // Clear data. void clear() { @@ -251,10 +260,17 @@ namespace yask { // Return dim posn or -1 if it doesn't exist. // Lookup by name. int lookup_posn(const std::string& dim) const { + + // First check pointers. + for (size_t i = 0; i < _q.size(); i++) { + auto& s = _q[i]; + if (s.getNamePtr() == &dim) + return int(i); + } + + // Then check full strings. for (size_t i = 0; i < _q.size(); i++) { auto& s = _q[i]; - - // Check for match of name. if (s.getName() == dim) return int(i); } diff --git a/src/compiler/lib/Cpp.cpp b/src/compiler/lib/Cpp.cpp index 45e09220..785ba0a4 100644 --- a/src/compiler/lib/Cpp.cpp +++ b/src/compiler/lib/Cpp.cpp @@ -125,7 +125,7 @@ namespace yask { // x=>x_elem, y=>(y_elem+2), z=>(z_elem+1) in var-point // index args. VarMap vMap; - for (auto& dim : vecPoint.getDims()) { + for (auto& dim : vecPoint) { auto& dname = dim.getName(); int dofs = dim.getVal(); @@ -692,7 +692,7 @@ namespace yask { auto& fold = getFold(); os << "\n // Element indices derived from vector indices.\n"; int i = 0; - for (auto& dim : fold.getDims()) { + for (auto& dim : fold) { auto& dname = dim.getName(); string ename = dname + _elemSuffix; string cap_dname = PrinterBase::allCaps(dname); diff --git a/src/compiler/lib/Eqs.cpp b/src/compiler/lib/Eqs.cpp index d53fe06b..18f16f64 100644 --- a/src/compiler/lib/Eqs.cpp +++ b/src/compiler/lib/Eqs.cpp @@ -209,7 +209,7 @@ namespace yask { " cannot have a step condition"); // LHS must have all domain dims. - for (auto& dd : dims._domainDims.getDims()) { + for (auto& dd : dims._domainDims) { auto& dname = dd.getName(); numExprPtr dexpr = op1->getArg(dname); if (!dexpr) @@ -580,7 +580,7 @@ namespace yask { // dim is a simple offset. For example, in var dim 'x', the // index in the corresponding posn must be 'x', 'x+n', or 'x-n'. int fdoffsets = 0; - for (auto fdim : _dims._foldGT1.getDims()) { + for (auto fdim : _dims._foldGT1) { auto& fdname = fdim.getName(); if (gp->getArgOffsets().lookup(fdname)) fdoffsets++; diff --git a/src/compiler/lib/Eqs.hpp b/src/compiler/lib/Eqs.hpp index 3e76167f..51dd0b49 100644 --- a/src/compiler/lib/Eqs.hpp +++ b/src/compiler/lib/Eqs.hpp @@ -273,15 +273,16 @@ namespace yask { // Want to keep original order as much as possible. // Only reorder if dependencies are in conflict. - // Scan from beginning to end. - for (size_t i = 0; i < _all.size(); i++) { - auto& oi = _all.at(i); + // Scan from beginning to next-to-last. + for (size_t i = 0; i < _all.size() - 1; i++) { // Repeat until no dependent found. bool done = false; while (!done) { // Does obj[i] depend on any obj after it? + auto& oi = _all.at(i); + done = true; for (size_t j = i+1; j < _all.size(); j++) { auto& oj = _all.at(j); @@ -296,16 +297,13 @@ namespace yask { } // Swap them. - auto temp = oi; - oi = oj; - oj = temp; + _all.swap(i, j); // Start over at index i. done = false; break; } } - done = true; } } } diff --git a/src/compiler/lib/Expr.hpp b/src/compiler/lib/Expr.hpp index 94a4cec7..2b472eaa 100644 --- a/src/compiler/lib/Expr.hpp +++ b/src/compiler/lib/Expr.hpp @@ -865,7 +865,7 @@ namespace yask { // Set given args to be given offsets. virtual void setArgOffsets(const IntTuple& offsets) { - for (auto ofs : offsets.getDims()) + for (auto ofs : offsets) setArgOffset(ofs); } diff --git a/src/compiler/lib/Settings.cpp b/src/compiler/lib/Settings.cpp index 6b7560ea..f93a5b1c 100644 --- a/src/compiler/lib/Settings.cpp +++ b/src/compiler/lib/Settings.cpp @@ -127,7 +127,7 @@ namespace yask { // Extract domain fold lengths based on cmd-line options. IntTuple foldOpts; - for (auto& dim : _domainDims.getDims()) { + for (auto& dim : _domainDims) { auto& dname = dim.getName(); // Was folding specified for this dim? @@ -193,7 +193,7 @@ namespace yask { // sizes. else { IntTuple innerOpts; - for (auto& dim : _domainDims.getDims()) { + for (auto& dim : _domainDims) { auto& dname = dim.getName(); if (dname == _innerDim) continue; @@ -208,7 +208,7 @@ namespace yask { } // Put them into the fold. - for (auto& dim : _domainDims.getDims()) { + for (auto& dim : _domainDims) { auto& dname = dim.getName(); if (dname == _innerDim) _fold[dname] = inner_sz; @@ -227,7 +227,7 @@ namespace yask { } // Set foldGT1. - for (auto i : _fold.getDims()) { + for (auto i : _fold) { auto& dname = i.getName(); auto& val = i.getVal(); if (val > 1) @@ -254,7 +254,7 @@ namespace yask { } // Create final cluster lengths based on cmd-line options. - for (auto& dim : settings._clusterOptions.getDims()) { + for (auto& dim : settings._clusterOptions) { auto& dname = dim.getName(); int mult = dim.getVal(); diff --git a/src/compiler/lib/Var.cpp b/src/compiler/lib/Var.cpp index 574790dc..acbd9993 100644 --- a/src/compiler/lib/Var.cpp +++ b/src/compiler/lib/Var.cpp @@ -141,7 +141,7 @@ namespace yask { } // Find the number of folded dims used in this var. - for (auto fdim : dims._foldGT1.getDims()) { + for (auto fdim : dims._foldGT1) { auto& fdname = fdim.getName(); // Search for dim in var. @@ -203,7 +203,7 @@ namespace yask { for (auto& i1 : m1) { auto& step = i1.first; const IntTuple& ohalos = i1.second; - for (auto& dim : ohalos.getDims()) { + for (auto& dim : ohalos) { auto& dname = dim.getName(); auto& val = dim.getVal(); @@ -245,7 +245,7 @@ namespace yask { int l1Dist = 0; // Update halo vals. - for (auto& dim : offsets.getDims()) { + for (auto& dim : offsets) { auto& dname = dim.getName(); int val = dim.getVal(); bool left = val <= 0; @@ -283,7 +283,7 @@ namespace yask { // Update const indices based on 'indices'. void Var::updateConstIndices(const IntTuple& indices) { - for (auto& dim : indices.getDims()) { + for (auto& dim : indices) { auto& dname = dim.getName(); int val = dim.getVal(); diff --git a/src/compiler/lib/Var.hpp b/src/compiler/lib/Var.hpp index 2a652c20..f6f77617 100644 --- a/src/compiler/lib/Var.hpp +++ b/src/compiler/lib/Var.hpp @@ -244,7 +244,9 @@ namespace yask { // A list of vars. This holds pointers to vars defined by the stencil // class in the order in which they are added via the INIT_VAR_* macros. - class Vars : public vector_set { + class Vars { + vector_set _vars; + public: Vars() {} @@ -252,11 +254,34 @@ namespace yask { // Copy ctor. // Copies list of var pointers, but not vars (shallow copy). - Vars(const Vars& src) : vector_set(src) {} + Vars(const Vars& src) : _vars(src._vars) {} + + // STL methods. + size_t size() const { + return _vars.size(); + } + Var* at(size_t i) { + return _vars.at(i); + } + const Var* at(size_t i) const { + return _vars.at(i); + } + vector::const_iterator begin() const { + return _vars.begin(); + } + vector::const_iterator end() const { + return _vars.end(); + } + size_t count(Var* p) const { + return _vars.count(p); + } + void insert(Var* p) { + _vars.insert(p); + } // Determine whether each var can be folded. virtual void setFolding(const Dimensions& dims) { - for (auto gp : *this) + for (auto gp : _vars) gp->setFolding(dims); } }; diff --git a/src/compiler/lib/Vec.cpp b/src/compiler/lib/Vec.cpp index 15f1d797..c0f27984 100644 --- a/src/compiler/lib/Vec.cpp +++ b/src/compiler/lib/Vec.cpp @@ -78,7 +78,7 @@ namespace yask { // Find aligned vector indices and offsets // for this one point. IntTuple vecOffsets, vecLocation; - for (auto& dim : offsets.getDims()) { + for (auto& dim : offsets) { auto& dname = dim.getName(); // length of this dimension in fold, if it exists. diff --git a/src/compiler/lib/Vec.hpp b/src/compiler/lib/Vec.hpp index 711e1f4d..1f576892 100644 --- a/src/compiler/lib/Vec.hpp +++ b/src/compiler/lib/Vec.hpp @@ -158,7 +158,7 @@ namespace yask { // calc footprint in each dim. map footprints; - for (auto& dim : _dims._fold.getDims()) { + for (auto& dim : _dims._fold) { auto& dname = dim.getName(); // Make set of aligned vecs projected in this dir. @@ -176,7 +176,7 @@ namespace yask { separator << getNumPoints() << separator << getNumAlignedVecs() << separator << numBlends; - for (auto& dim : _dims._fold.getDims()) + for (auto& dim : _dims._fold) os << separator << footprints[dim.getName()]; os << endl; } diff --git a/src/compiler/lib/YaskKernel.cpp b/src/compiler/lib/YaskKernel.cpp index 0b4b8ee0..db248265 100644 --- a/src/compiler/lib/YaskKernel.cpp +++ b/src/compiler/lib/YaskKernel.cpp @@ -33,7 +33,7 @@ namespace yask { void YASKCppPrinter::printIndices(ostream& os) const { os << endl << " // Extract individual indices.\n"; int i = 0; - for (auto& dim : _dims._stencilDims.getDims()) { + for (auto& dim : _dims._stencilDims) { auto& dname = dim.getName(); os << " idx_t " << dname << " = idxs[" << i << "];\n"; i++; @@ -94,12 +94,12 @@ namespace yask { os << "\n// Number of domain dimensions:\n" "#define NUM_DOMAIN_DIMS " << _dims._domainDims.size() << "\n"; int i = 0; - for (auto& dim : _dims._domainDims.getDims()) { + for (auto& dim : _dims._domainDims) { auto& dname = dim.getName(); os << "#define DOMAIN_DIM_IDX_" << dname << " (" << (i++) << ")\n"; } i = 0; - for (auto& dim : _dims._stencilDims.getDims()) { + for (auto& dim : _dims._stencilDims) { auto& dname = dim.getName(); os << "#define STENCIL_DIM_IDX_" << dname << " (" << (i++) << ")\n"; } @@ -122,7 +122,7 @@ namespace yask { // Vec/cluster lengths. auto nvec = _dims._foldGT1.getNumDims(); os << "\n// One vector fold: " << _dims._fold.makeDimValStr(" * ") << endl; - for (auto& dim : _dims._fold.getDims()) { + for (auto& dim : _dims._fold) { auto& dname = dim.getName(); string ucDim = allCaps(dname); os << "#define VLEN_" << ucDim << " (" << dim.getVal() << ")" << endl; @@ -168,7 +168,7 @@ namespace yask { os << endl; os << "// Cluster multipliers of vector folds: " << _dims._clusterMults.makeDimValStr(" * ") << endl; - for (auto& dim : _dims._clusterMults.getDims()) { + for (auto& dim : _dims._clusterMults) { auto& dname = dim.getName(); string ucDim = allCaps(dname); os << "#define CMULT_" << ucDim << " (" << @@ -910,24 +910,24 @@ namespace yask { os << " p->_step_dim = \"" << _dims._stepDim << "\";\n" " p->_inner_dim = \"" << _dims._innerDim << "\";\n"; - for (auto& dim : _dims._domainDims.getDims()) { + for (auto& dim : _dims._domainDims) { auto& dname = dim.getName(); os << " p->_domain_dims.addDimBack(\"" << dname << "\", 0);\n"; } - for (auto& dim : _dims._stencilDims.getDims()) { + for (auto& dim : _dims._stencilDims) { auto& dname = dim.getName(); os << " p->_stencil_dims.addDimBack(\"" << dname << "\", 0);\n"; } - for (auto& dim : _dims._miscDims.getDims()) { + for (auto& dim : _dims._miscDims) { auto& dname = dim.getName(); os << " p->_misc_dims.addDimBack(\"" << dname << "\", 0);\n"; } - for (auto& dim : _dims._fold.getDims()) { + for (auto& dim : _dims._fold) { auto& dname = dim.getName(); auto& dval = dim.getVal(); os << " p->_fold_pts.addDimBack(\"" << dname << "\", " << dval << ");\n"; } - for (auto& dim : _dims._foldGT1.getDims()) { + for (auto& dim : _dims._foldGT1) { auto& dname = dim.getName(); auto& dval = dim.getVal(); os << " p->_vec_fold_pts.addDimBack(\"" << dname << "\", " << dval << ");\n"; @@ -935,12 +935,12 @@ namespace yask { string ffi = (_dims._fold.isFirstInner()) ? "true" : "false"; os << " p->_fold_pts.setFirstInner(" << ffi << ");\n" " p->_vec_fold_pts.setFirstInner(" << ffi << ");\n"; - for (auto& dim : _dims._clusterPts.getDims()) { + for (auto& dim : _dims._clusterPts) { auto& dname = dim.getName(); auto& dval = dim.getVal(); os << " p->_cluster_pts.addDimBack(\"" << dname << "\", " << dval << ");\n"; } - for (auto& dim : _dims._clusterMults.getDims()) { + for (auto& dim : _dims._clusterMults) { auto& dname = dim.getName(); auto& dval = dim.getVal(); os << " p->_cluster_mults.addDimBack(\"" << dname << "\", " << dval << ");\n"; diff --git a/src/kernel/lib/alloc.cpp b/src/kernel/lib/alloc.cpp index 92f0608d..58e1d3d3 100644 --- a/src/kernel/lib/alloc.cpp +++ b/src/kernel/lib/alloc.cpp @@ -307,7 +307,7 @@ namespace yask { IdxTuple my_halo_sizes, neigh_halo_sizes; IdxTuple first_inner_idx, last_inner_idx; IdxTuple first_outer_idx, last_outer_idx; - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); // Only consider domain dims that are used in this var. @@ -415,7 +415,7 @@ namespace yask { // to be so. // TODO: add a heuristic to avoid increasing by a large factor. if (var_vec_ok) { - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); if (gp->is_dim_used(dname)) { auto vlen = gp->_get_var_vec_len(dname); @@ -853,7 +853,7 @@ namespace yask { auto& gb = gp->gb(); // Loop through each domain dim. - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); if (gp->is_dim_used(dname)) { diff --git a/src/kernel/lib/auto_tuner.cpp b/src/kernel/lib/auto_tuner.cpp index f8fca528..dfea19ae 100644 --- a/src/kernel/lib/auto_tuner.cpp +++ b/src/kernel/lib/auto_tuner.cpp @@ -275,7 +275,7 @@ namespace yask { // Pick better starting point if needed. if (!checkSizes(center_sizes)) { - for (auto dim : center_sizes.getDims()) { + for (auto dim : center_sizes) { auto& dname = dim.getName(); auto& dval = dim.getVal(); if (dname != step_dim) { @@ -352,7 +352,7 @@ namespace yask { IdxTuple bsize(center_sizes); bool ok = true; int mdist = 0; // manhattan dist from center. - for (auto odim : ofs.getDims()) { + for (auto odim : ofs) { auto& dname = odim.getName(); // a domain-dim name. auto& dofs = odim.getVal(); // always [0..2]. diff --git a/src/kernel/lib/context.hpp b/src/kernel/lib/context.hpp index 23f88c9b..6dc2c975 100644 --- a/src/kernel/lib/context.hpp +++ b/src/kernel/lib/context.hpp @@ -605,17 +605,11 @@ namespace yask { } virtual std::vector get_domain_dim_names() const { STATE_VARS_CONST(this); - std::vector ddims; - for (auto& dim : dims->_domain_dims.getDims()) - ddims.push_back(dim.getName()); - return ddims; + return domain_dims.getDimNames(); } virtual std::vector get_misc_dim_names() const { STATE_VARS_CONST(this); - std::vector mdims; - for (auto& dim : dims->_misc_dims.getDims()) - mdims.push_back(dim.getName()); - return mdims; + return misc_dims.getDimNames(); } virtual idx_t get_first_rank_domain_index(const std::string& dim) const; diff --git a/src/kernel/lib/settings.cpp b/src/kernel/lib/settings.cpp index e97ab65f..bb265eb0 100644 --- a/src/kernel/lib/settings.cpp +++ b/src/kernel/lib/settings.cpp @@ -290,7 +290,7 @@ namespace yask { // Add step + domain vars. vector multi_vars; string multi_help; - for (auto& dim : var.getDims()) { + for (auto& dim : var) { auto& dname = dim.getName(); if (!allow_step && _dims->_step_dim == dname) continue; @@ -585,7 +585,7 @@ namespace yask { const IdxTuple& mults, const std::string& step_dim) { idx_t prod = 1; - for (auto& dim : inner_sizes.getDims()) { + for (auto& dim : inner_sizes) { auto& dname = dim.getName(); if (dname == step_dim) continue; diff --git a/src/kernel/lib/setup.cpp b/src/kernel/lib/setup.cpp index 7ba01872..0694857b 100644 --- a/src/kernel/lib/setup.cpp +++ b/src/kernel/lib/setup.cpp @@ -451,7 +451,7 @@ namespace yask { max_halos = dims->_domain_dims; // Loop through each domain dim. - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); // Each non-scratch var. @@ -513,7 +513,7 @@ namespace yask { state->_use_pack_tuners = opts->_allow_pack_tuners && (tb_steps == 0) && (stPacks.size() > 1); // Calculate angles and related settings. - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); auto rnsize = opts->_region_sizes[dname]; auto rksize = opts->_rank_sizes[dname]; @@ -565,7 +565,7 @@ namespace yask { assert(gp); // Loop through each domain dim. - for (auto& dim : domain_dims.getDims()) { + for (auto& dim : domain_dims) { auto& dname = dim.getName(); if (gp->is_dim_used(dname)) { // Set extensions to be the same as the global ones. diff --git a/src/kernel/lib/yk_var.cpp b/src/kernel/lib/yk_var.cpp index bd80fc31..70953d2a 100644 --- a/src/kernel/lib/yk_var.cpp +++ b/src/kernel/lib/yk_var.cpp @@ -94,7 +94,7 @@ namespace yask { auto* dims = get_dims().get(); const auto& domain_dims = dims->_domain_dims; - for (auto& d : domain_dims.getDims()) { + for (auto& d : domain_dims) { auto& dname = d.getName(); if (!_ggb->is_dim_used(dname)) return false;