[Mlir-commits] [mlir] [mlir][sparse] update doc for new surface syntax encoding (PR #67072)

Aart Bik llvmlistbot at llvm.org
Thu Sep 21 16:31:47 PDT 2023


================
@@ -107,79 +100,71 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
   let mnemonic = "encoding";
 
   let description = [{
-    An attribute to encode TACO-style information on sparsity properties
-    of tensors. The encoding is eventually used by a **sparse compiler**
-    pass to generate sparse code fully automatically for all tensor
-    expressions that involve tensors with a sparse encoding. Compiler
-    passes that run before this sparse compiler pass need to be
-    aware of the semantics of tensor types with such an encoding.
-
-    Each sparse tensor comes equipped with two different sets of axes for
-    describing the tensor's multi-dimensional structure.  We use the term
-    "dimension" to refer to the axes of the semantic tensor itself; whereas,
-    we use the term "level" to refer to the axes of the storage scheme,
-    which is the operational representation of that tensor.  Therefore,
-    the fields of the encoding attribute (further explained below) satisfy
-    the following correspondences:
-
-    - Dimensions:
-        - the shape of the tensor type
-        - the `dimSlices` field
-        - the arguments of the `dimToLvl` field
-    - Levels:
-        - the results of the `dimToLvl` field
-        - the `lvlTypes` field
-
-    The attribute consists of the following fields.
-
-    - Level-type for each level of a tensor type:
-        - **dense** : all entries along this level are stored.
-        - **compressed** : only nonzeros along this level are stored.
-        - **singleton** : a variant of the compressed level-format,
-          for when coordinates are guaranteed to have no siblings at this level.
-      By default, each level-type has the property of being unique (no
-      duplicates at that level) and ordered (coordinates appear sorted
-      at that level).  The following two suffixes can be used to specify
-      that the level should instead be non-unique (duplicates may appear)
-      and/or non-ordered (coordinates may appear unsorted).
-        - **-nu** : not unique
-        - **-no** : not ordered
-      Currently, these suffixes (if present) must appear in this order.
-      In the future, we may introduce additional level-types and
-      properties, and split up how the level-format and properties are
-      specified rather than using this suffix mechanism.
-
-    - An optional affine map from dimension-coordinates to level-coordinates;
-      defaulting to the identity map.  For example, given a 2-d tensor:
-      `(i, j) -> (i, j)` specifies row-wise storage, `(i, j) -> (j, i)`
-      specifies column-wise storage, and
-      `(i, j) -> (i floordiv 2, j floordiv 3, i mod 2, j mod 3)`
-      specifies 2x3 block-sparsity.  For block-sparsity, blocks are typically
-      stored with compression while dense storage is used within each block
-      (although hybrid schemes are possible as well).
-
-      (The following will be corrected in an upcoming change that completely
-      overhauls the syntax of this attribute.)
-
-      The dimToLvl mapping also provides a notion of "counting a
-      dimension", where every stored element with the same coordinate
-      is mapped to a new slice.  For instance, ELL storage of a 2-d
-      tensor can be defined with the mapping `(i, j) -> (#i, i, j)`
-      using the notation of [Chou20].  Lacking the `#` symbol in MLIR's
-      affine mapping, we use a free symbol `c` to define such counting,
-      together with a constant that denotes the number of resulting
-      slices.  For example, the mapping `(i, j)[c] -> (c * 3 * i, i, j)`
-      with the level-types `["dense", "dense", "compressed"]` denotes ELL
-      storage with three jagged diagonals that count the dimension `i`.
-
-    - The required bitwidth for "position" storage (integral offsets
+    An attribute to encode information on sparsity properties of tensors, inspired
+    by the TACO formalization of sparse tensors. This encoding is eventually used
+    by a **sparsifier** pass to generate sparse code fully automatically from a
+    sparsity-agnostic representation of the computation, i.e., an implicit sparse
+    representation is converted to an explicit sparse representation where co-iterating
+    loops operate on sparse storage formats rather than tensors with a sparsity
+    encoding. Compiler passes that run before this sparse compiler pass need to
+    be aware of the semantics of tensor types with such a sparsity encoding.
+
+    In this encoding, we use `dimension` to refer to the axes of the semantic tensor,
+    and `level` to refer to the axes of the actual storage format, i.e., the
+    operational representation of the sparse tensor in memory. The number of
+    dimensions is usually the same as the number of levels (e.g. CSR storage format).
+    However, the encoding can also map dimensions to higher-order levels (for example,
+    to encode a block-sparse BSR storage format) or to lower-order levels
+    (for example, to linearize dimensions in the storage).
+
+    The encoding contains a `map` that provides the following:
+
+    - An ordered sequence of dimension specifications, each of which defines:
+      - the the dimension-size (implicit from the tensor’s dimension-shape)
+      - an optional **dimension-expression**
+    - An ordered sequence of level specifications, each of which includes a required
+      **level-type**, which defines how the level should be stored. Each level-type
+      consists of:
+      - a required **level-format**
+      - a collection of **level-properties** that apply to the level-format
+      - a **level-expression**, which defines what is stored
+
+    Each level-expression is an affine expression over dimension-variables. Thus, the
+    level-expressions collectively define an affine map from dimension-coordinates to
+    level-coordinates. The dimension-expressions collectively define the inverse map,
+    which only needs to be provided for elaborate cases where it cannot be inferred
+    automatically. Within the sparse storage format, we refer to indices that are
+    stored explicitly as `coordinates` and indices into the storage format as `positions`.
+
+    The supported level-formats are the following:
+
+    - **dense** : all entries along this level are stored
+    - **compressed** : only nonzeros along this level are stored
+    - **singleton** : a variant of the compressed format, where coordinates have no siblings
+
+    Different level-formats may have different collections of level-properties.
+    By default, each level-type has the property of being unique (no duplicate
+    coordinates at that level), ordered (coordinates appear sorted at that
+    level), and, for compression, storing the positions in a compact way where
+    an interval is defined by a lower bound "pos(i)" and an upper bound "pos(i+1)-1".
+    The following properties can be added to a level-format to change this
+    default behavior:
+
+    - **nonunique** : duplicate coordinates may appear at the level
+    - **nonordered** : coordinates may appear in arbribratry order
+    - **high** : the upper bound is stored explicitly in a separate array
+    - **block2_4** : the compression uses a 2:4 encoding per 1x4 block
----------------
aartbik wrote:

Perhaps we have a choice here, but currently they are implemented as a property, i.e. we only have dense, compressed, and singleton as level formats. So the doc follows the current syntax (and we can update when needed)

https://github.com/llvm/llvm-project/pull/67072


More information about the Mlir-commits mailing list