/usr/include/hmat/cluster_tree.hpp is in libhmat-oss-dev 1.0.4-2ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | /*
HMat-OSS (HMatrix library, open source software)
Copyright (C) 2014-2015 Airbus Group SAS
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
http://github.com/jeromerobert/hmat-oss
*/
/*! \file
\ingroup HMatrix
\brief Spatial cluster tree for the Dofs.
*/
#ifndef _CLUSTER_TREE_HPP
#define _CLUSTER_TREE_HPP
#include "tree.hpp"
#include <vector>
#include <cmath>
extern size_t maxElementsPerBlock;
/*! \brief Class representing a 3D point.
*/
class Point {
public:
union {
struct {
double x, y, z; /// Coordinates
};
double xyz[3]; /// Idem
};
Point(double _x = 0., double _y = 0., double _z = 0.) : x(_x), y(_y), z(_z) {}
/*! \brief Return d(this, other)
*/
inline double distanceTo(const Point &other) const {
double result = 0.;
double difference = 0.;
difference = x - other.x;
result += difference * difference;
difference = y - other.y;
result += difference * difference;
difference = z - other.z;
result += difference * difference;
return sqrt(result);
}
};
/*! \brief Data held by a node of a \a ClusterTree.
*/
class ClusterData {
public:
/// Global indices array
int *indices;
/// offset of the start of this node's data in indices
size_t offset;
/// length of this node's data in indices
size_t n;
const std::vector<Point>* points;
public:
/*! \brief Compare two indices set for equality.
*/
bool operator==(const ClusterData& o) const;
/*! \brief Return true if this is a subset of o.
\param o ClusterData
\return true if this is a subset of o
*/
bool isSubset(const ClusterData& o) const;
/*! \brief Return true if this is a strict subset of o.
*/
bool isStrictSubset(const ClusterData& o) const {
return isSubset(o) && (!(*this == o));
};
/*! \brief Return o.isSubset(*this)
*/
bool isSuperSet(const ClusterData& o) const;
/*! \brief Return o.isStrictSubset(*this)
*/
bool isStrictSuperSet(const ClusterData& o) const {
return isSuperSet(o) && (!(*this == o));
};
/** Return true if two index sets intersect.
*/
bool intersects(const ClusterData& o) const;
/** Return the intersection of two index sets, NULL if the intersection is empty.
*/
const ClusterData* intersection(const ClusterData& o) const;
/** Compute the bounding box of a ClusterData set.
*/
void computeBoundingBox(Point boundingBox[2]) const;
ClusterData(int* _indices, size_t _offset, size_t _n, const std::vector<Point>* _points)
: indices(_indices), offset(_offset), n(_n), points(_points) {}
};
/*! \brief Comparateur pour deux indices selon une de leur coordonnee.
On utilise les templates pour eviter un trop grand cout a
l'execution ou le copier-coller, avec pour le parametre du template :
- 0 pour une comparaison selon x
- 1 pour une comparaison selon y
- 2 pour une comparaison selon z
*/
template<int N> class IndicesComparator {
private:
ClusterData& data;
public:
IndicesComparator(ClusterData& _data) : data(_data) {}
bool operator() (int i, int j) {
return (*data.points)[i].xyz[N] < (*data.points)[j].xyz[N];
}
};
/*! \brief Abstract Base Class for the Cluster trees.
This class defines the index set division of a problem. Several divisions
being possible, this is an abstract class. It however only allows bisection of
the index set.
\warning During the tree creation, it is mandatory to call
ClusterTree::divide() on the newly created tree, to really create the tree
structure.
*/
class ClusterTree : public Tree<2> {
public:
/*! min and max points */
Point boundingBox[2];
/*! Admissibility criteria for the tree nodes. */
static double eta;
/*! Data */
ClusterData data;
protected:
/*! Bounding boxes of the children */
Point childrenBoundingBoxes[2][2];
/*! Max number of Dofs in a leaf */
int threshold;
public:
/*! \brief Create a leaf.
\param _boundingBox bounding box of this leaf
\param clusterData data held by this leaf
\param _threshold max number of indices in a leaf. Used for the recursive division.
*/
ClusterTree(Point _boundingBox[2], const ClusterData& _data, int _threshold);
/*! \brief Returns true if 2 nodes are admissible together.
This is used for the tree construction on which we develop the HMatrix.
Two leaves are admissible if they satisfy the criterion allowing the
compression of the resulting matrix block.
In the default implementation in the base class, the criterion kept is:
min (diameter (), other-> diameter ()) <= eta * distanceTo (other);
There is also a criterion of size on the resulting block, which
should not exceed 10000000 elements (160MB for double complex precision).
TODO: making the criterion adjustable.
\param other the other node of the couple.
\param eta a parameter used in the evaluation of the admissibility.
\return true if 2 nodes are admissible.
*/
bool isAdmissibleWith(const ClusterTree* other, double eta = 10.) const;
/*! \brief Returns the admissibility parameter eta corresponding to two clusters.
As described in \a ClusterTree::isAdmissibleWith documentation,
this criteria is defined by:
eta = min(diameter(), other->diameter()) / distanceTo(other);
The lower it is, the farther away are the two boxes. It is thus
linked with the compression ratio one can expect from a block, the
lower eta is, the more the block can be compressed. It can be used
as a parameter in a crude a-priori work estimation method.
*/
double getEta(const ClusterTree* other) const;
/*! \brief Divide the tree to create its final structure.
\warning It is mandatory to call this function before using a newly created tree.
*/
void divide();
/*! \brief Return a copy to this.
*/
ClusterTree* copy(const ClusterTree* copyFather=NULL) const;
protected:
/*! Diameter of the node */
double diameter() const;
/*! Distance to an other node */
double distanceTo(const ClusterTree* other) const;
/*! Returns true if a point is inside a given children bounding box.
\param p The points
\param index the index of the children bounding box to consider.
*/
inline bool isPointInBox(const Point p, int boxIndex) const {
Point box[2] = {childrenBoundingBoxes[boxIndex][0],
childrenBoundingBoxes[boxIndex][1]};
return ((p.x >= box[0].x) && (p.x <= box[1].x)
&& (p.y >= box[0].y) && (p.y <= box[1].y)
&& (p.z >= box[0].z) && (p.z <= box[1].z));
}
/** Return the largest dimension of the node bounding box.
*/
int largestDimension() const;
/** Sort the ClusterData indices of this node according to a given dimension.
\parak dim The dimension.
*/
void sortByDimension(int dim);
/** Find the index of the separation between the two sons.
*/
virtual int findSeparatorIndex() const = 0;
/*! \brief Make a new ClusterTree*.
This function has the same arguments as \a
ClusterTree::ClusterTree(). It is used to make an instance of the
right derived type.
*/
virtual ClusterTree* make(Point _boundingBox[2], const ClusterData& _data, int _threshold) const = 0;
};
/*! \brief Creating tree by geometric binary division according to
the largest dimension.
For this tree, if a leaf has too many DOFs, the division is done by
dividing the bounding box in the middle of its biggest dimension.
The boxes of children are resized to the real dimension of the DOFs.
This method ensures that both 2 children won't be empty, but not the
equal repartition of DOFs on both sides of the boundary.
*/
class GeometricBisectionClusterTree : public ClusterTree {
public:
GeometricBisectionClusterTree(Point _boundingBox[2],
const ClusterData& _data, int _threshold)
: ClusterTree(_boundingBox, _data, _threshold) {}
protected:
int findSeparatorIndex() const;
ClusterTree* make(Point _boundingBox[2], const ClusterData& _data, int _threshold) const;
};
/*! \brief Creating tree by median division.
For the division of a leaf, we chose the biggest dimension
of bounding box and divide it according to this axis. The DOFs are
sorted by the increasing order on this direction, and are divided
in the median of this axis. This method ensures that the children
will have equal number of DOFs, but desn't respect their size criterion.
The bounding boxes of the children are resized to the necessary size.
*/
class MedianBisectionClusterTree : public ClusterTree {
public:
MedianBisectionClusterTree(Point _boundingBox[2],
const ClusterData& _data, int _threshold)
: ClusterTree(_boundingBox, _data, _threshold) {}
protected:
int findSeparatorIndex() const;
ClusterTree* make(Point _boundingBox[2], const ClusterData& _data, int _threshold) const;
};
class HybridBisectionClusterTree : public ClusterTree {
public:
HybridBisectionClusterTree(Point _boundingBox[2],
const ClusterData& _data, int _threshold)
: ClusterTree(_boundingBox, _data, _threshold) {}
protected:
int findSeparatorIndex() const;
ClusterTree* make(Point _boundingBox[2], const ClusterData& _data, int _threshold) const;
};
#endif
|