diff --git a/.github/workflows/build-spec.yml b/.github/workflows/build-spec.yml index a1ef947..1e3ebf6 100644 --- a/.github/workflows/build-spec.yml +++ b/.github/workflows/build-spec.yml @@ -6,8 +6,7 @@ jobs: Build-GraphBLAS-Spec: runs-on: ubuntu-latest container: - image: benbrock/graphblas-cpp:build-docs-0.3 - if: ${{ github.ref != 'refs/heads/gh-pages' }} + image: benbrock/graphblas-cpp:build-docs-0.2 steps: - name: Check out repository code uses: actions/checkout@v3 @@ -18,6 +17,8 @@ jobs: mkdir graphblas-cpp-spec cp graphblas.pdf graphblas-cpp-spec cp graphblas.html graphblas-cpp-spec + mkdir github-pages + cp graphblas.html github-pages/index.html - name: Check on spec run: ls $GITHUB_WORKSPACE/markdown - name: Archive GraphBLAS C++ Spec @@ -26,31 +27,21 @@ jobs: name: graphblas-cpp-spec path: | ${{ github.workspace }}/markdown/graphblas-cpp-spec - + - name: Archive GitHub Pages + uses: actions/upload-artifact@v2 + with: + name: github-pages + path: | + ${{ github.workspace }}/markdown/github-pages Deploy-GitHub-Pages: - runs-on: ubuntu-latest needs: Build-GraphBLAS-Spec + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages if: ${{ github.ref == 'refs/heads/master' }} steps: - - name: Checkout gh-pages - uses: actions/checkout@v3 - with: - ref: gh-pages - path: gh-pages - - name: Download artifact - uses: actions/download-artifact@v2 - with: - name: graphblas-cpp-spec - - name: Publish to GitHub Pages - run: | - cd $GITHUB_WORKSPACE - cp graphblas.html gh-pages/docs/index.html - cd gh-pages - find * - git config user.name github-actions - git config user.email github-actions@github.com - git add . - # Ignore errors because no updates returns an error status. - git commit --reset-author --amend -m "Update from github actions" - git push --force origin gh-pages - + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v1 diff --git a/README.md b/README.md deleted file mode 100644 index 629fd88..0000000 --- a/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# GraphBLAS C++ Specification - -Click here for the [most recent HTML draft](https://graphblas.org/graphblas-api-cpp) and [most recent PDF draft](https://github.com/GraphBLAS/graphblas-api-cpp/actions/workflows/build-spec.yml). - -The currently under development GraphBLAS C++ API aims to provide a C++ API for implementing graph algorithms in the language of linear algebra, and is part of the larger [GraphBLAS](https://graphblas.github.io/) project. The API provides data structures for storing matrices and vectors, as well as a collection of algorithms, such as generalized matrix multiplication, that can be used with custom or pre-defined operators, monoids, and semirings. - -The standard document itself can be found in the folder [markdown](https://github.com/GraphBLAS/graphblas-api-cpp/tree/master/markdown), -while minutes for meetings of the GraphBLAS C++ API subcommittee can be found in the folder [minutes](https://github.com/GraphBLAS/graphblas-api-cpp/tree/master/minutes). - -## Brief API Example -```C++ - // Create a GraphBLAS matrix of size 128 x 128. - grb::matrix x({128, 128}); - - // Write to elements along the diagonal. - for (size_t i = 0; i < 128; i++) { - x[{i, i}] = i*i; - } - - float sum = 0; - // Sum up all the elements stored in the matrix. - for (auto&& [index, value] : x) { - sum += value; - } -``` - - -## Libraries - -* [rgri](https://github.com/BenBrock/rgri) is being developed as a reference implementation alongside the API. -* [GBTL](https://github.com/cmu-sei/gbtl) has heavily influenced the development of the C++ API, and is also being updated alongside the development of the API. - -## Citation -To cite the [GraphBLAS C++ Specification](https://github.com/GraphBLAS/graphblas-api-cpp): - -Benjamin Brock, Scott McMillan, Aydın Buluc ̧, Timothy Mattson, and Jose ́ Moreira. GraphBLAS C++ specification. https://github.com/ GraphBLAS/graphblas-api-cpp, 2022. - -```bibtex -@misc{graphblascppspec, - title={Graph{BLAS} {C}++ Specification}, - author={Brock, Benjamin and McMillan, Scott and Bulu\c{c}, Ayd{\i}n and Mattson, Timothy and Moreira, Jos{\'e}}, - howpublished={\url{https://github.com/GraphBLAS/graphblas-api-cpp}}, - volume = {Version 1.0}, - year={2023} -} -``` diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..ffff7c4 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,4166 @@ + + + + + + + GraphBLAS C++ API Specification v1.0 + + + + + +
+

GraphBLAS C++ API Specification v1.0

+
+ +
+

Intro

+

The GraphBLAS standard defines a set of generalized matrix and vector +operations based on semiring algebraic structures. These operations can +be used to express a wide variety of graph algorithms. This +specification document defines the C++ programming interface for the +GraphBLAS standard, referred to as the . The GraphBLAS C++ API defines a +collection of data structures, algorithms, views, operators, and +concepts for implementing graph algorithms. These API components are +based around mathematical objects, such as matrices and vectors, and +operations, such as generalized matrix multiplication and element-wise +operations. The GraphBLAS Math +Specification provides a complete specification of the mechanics of +these structures and operations, and provides a rigorous mathematical +definition of the operations and data structures provided in this +specification.

+

Data Structures

+

This specification provides data structures for storing matrices and +vectors. These implement the matrix and vector range concepts also defined in this specification.

+

Matrices

+

Matrices are two-dimensional collections of sparse values. Each +matrix has a defined number of rows and columns, which define its . In +addition, each matrix has a defined number of , which are indices inside +the bounds of the matrix which actually contain scalar values. A matrix +has a fixed , which is the type of the stored values, as well as an , +which is the type of the indices.

+

GraphBLAS matrices are sparse, consist of a well-defined set of +stored values, and have no implicit zero value for empty indices. As +such, operations may not arbitrarily insert explicit zero values into +the matrix, but must produce an output with the exact set of values as +specified by the GraphBLAS Math Specification.

+

The GraphBLAS matrix data structure defined in this specification, +grb::matrix, provides mechanisms for creating, +manipulating, and iterating through GraphBLAS matrices. It also includes +a mechanism for influencing the storage format through compile-time +hints. GraphBLAS operations that accept matrices can be called with +other types so long as they fulfill the GraphBLAS matrix concepts.

+

Vectors

+

Vectors are one-dimensional collections of sparse values. Each vector +has a defined number of indices, which defines its shape. Similarly, it +has a defined number of stored stored values, which must lie at indices +within its shape. Its scalar values have a fixed scalar type, and it has +a fixed index type for storing indices. Vectors follow the same sparsity +rules as matrices, and similarly the GraphBLAS matrix concepts.

+

Concepts

+

The GraphBLAS C++ Specification defines matrix and vector concepts. +These define the interface that a type must support in order to be used +by GraphBLAS operations. The intention is that data structures defined +by other libraries may be used in GraphBLAS operations so long as they +define a small number of customization points that perform insert, find, +and iteration operations over the matrix or vector.

+

Version Conformance

+

A C++ GraphBLAS library should define the macro +GRAPHBLAS_CPP_VERSION to indicate its level of conformance +with the GraphBLAS C++ API. To indicate conformance with the GraphBLAS +0.1a draft specification, a library should provide the macro +GRAPHBLAS_CPP_VERSION with a value greater than or equal to +202207L.

+

Exposition Only

+
// Define the `GRAPHBLAS_CPP_VERSION` macro to indicate
+// conformance to the GraphBLAS 0.1 Draft Specification.
+#define GRAPHBLAS_CPP_VERSION 202207L
+

Basic Concepts

+

GraphBLAS defines a collection of objects, functions, and concepts to +facilitate the implementation of graph algorithms. These programming +facilities are further separated into GraphBLAS containers, +which include matrices and vectors, GraphBLAS operations, which +are algorithms such as matrix-vector multiplication that operate over +GraphBLAS containers, and GraphBLAS operators, which are binary +and unary operators that operate over scalar elements that may be held +in a container. The C++ API also defines a series of concepts +defining the interface a container or operator must fulfill in order to +to be used with a particular operation, as well as views, which +provide lazily evaluated, mutated views of a GraphBLAS object.

+

GraphBLAS Containers

+

GraphBLAS containers, which include matrices and vectors, are sparse +data structures holding a collection of stored scalar values. Each +GraphBLAS container has a shape, which defines the dimension(s) of the +object. Stored values can be inserted at indices within the dimensions +of the object. Since GraphBLAS containers are sparse, they keep explicit +track of which index locations in the object hold stored values. There +is no implied zero value associated with a GraphBLAS container, since +the annhilator value will change from operation to operation, and the +insertion of explicit “zeros” could cause incorrect results. As such, no +GraphBLAS operation will arbitrarily insert explicit zeros. In the +GraphBLAS C++ API, each container has associated with it a scalar type, +which is the type of the stored scalar values, as well as an index type, +which is the type used to indicate the locations of stored values, as +well as the matrix shape.

+

TODO: be more specific here. Could use some help from +math spec?

+

Matrices

+

GraphBLAS matrices are two-dimensional sparse arrays. As previously +discussed, they have a scalar type, which defines the type of scalar +values stored inside the matrix, as well as an index type, which is used +to refer to the row and column index of each stored value. For a matrix +type A, these types can be retrieved using the expression +grb::matrix_scalar_t<A> to retrieve the scalar type +and grb::matrix_index_t<A> to retrieve the index +type. In the GraphBLAS C++ API, matrices are associative arrays similar +to instantiations of std::unordered_map. They map keys, +which are row and column indices, to values, which are the stored scalar +values. Like the C++ standard library’s associative containers, +GraphBLAS matrices are ranges, and iterating through a GraphBLAS matrix +reveals a collection of tuples, with each tuple holding a key and value. +The key is a tuple-like type holding the row and column indices, and the +value is the stored scalar value. The row and column are provided only +as const references, while the value may be mutated. Matrices also +support insert, assign, and find operations to write or read to a +particular location in the matrix.

+

Vectors

+

GraphBLAS similars are analogous to matrices, except that they are +only one-dimensional sparse arrays. They hold a scalar type, which +defines the scalar values stored inside the vector, as well as an index +type, which holds the index of an element within the vector. For a +vector V, these types can be retrieved with the expressions +grb::vector_scalar_t<V> and +grb::vector_index_t<V>. Like matrices, vectors are +associative arrays, except that their key values are a single index type +element, and not a tuple. Like matrices, vectors are ranges, with the +value type being a tuple holding the index type and scalar type, with +only the scalar type being mutable if the vector is non-const. +Individual elements can be modified using insert, assign, and find.

+

grb::matrix

+
template <typename T,
+          std::integral I = std::size_t,
+          typename Hint = grb::sparse,
+          typename Allocator = std::allocator<T>>
+class grb::matrix;
+

Template Parameters

+

T - type of scalar values stored in the matrix

+

I - type, satisfying std::integral, used to +store indices in the matrix

+

Hint - one or a composition of compile-time hints that +may be used to affect the backend storage type

+

Allocator - allocator type used to allocate memory for +the matrix

+

Member Types

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Member TypeDefinition
scalar_typeT, the type of elements stored in the matrix
index_typeI, an integer type used to store matrix indices
key_typeA tuple-like type storing two index_type elements
map_typescalar_type
value_typegrb::matrix_entry<T, I>, a tuple-like type +storing the indices and the stored element
size_typeA large unsigned integer type, usually std::size_t
difference_typeA large signed integer type, usually +std::ptrdiff_t
allocator_typeAllocator
iteratorAn iterator type fulfilling std::forward_iterator
const_iteratorA const iterator fulfilling std::forward_iterator
referencegrb::matrix_reference<T, I>
const_referencegrb::matrix_reference<const T, I>
scalar_referenceReference to scalar_type
const_scalar_referenceConst reference to scalar_type
hint_typeHint
+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
(constructor)Constructs matrix
(destructor)Destructs matrix
operator=Assigns matrix
sizeNumber of stored elements in matrix
max_sizeReturns the maximum possible number of elements
emptyReturn whether the matrix is empty
shapeReturn the dimensions of the matrix
begin
cbegin
Returns iterator to beginning of container
end
cend
Returns iterator to one past last element in container
reshapeModify dimensions of the matrix
clearClears all elements from the container
insertInsert elements
insert_or_assignInserts or assigns elements
eraseErases elements
findFinds an element
atAccess element
operator[]Access or insert element
+

grb::matrix::matrix

+
matrix(const Allocator& alloc = Allocator());    (1)
+matrix(grb::index<index_type> shape,
+       const Allocator& alloc = Allocator());    (2)
+matrix(const matrix& other);                     (3)
+matrix(matrix&& other);                          (4)
+

Constructs new grb::matrix data structure.

+
    +
  1. Constructs an empty matrix of dimension 0 x 0.
  2. +
  3. Constructs an empty matrix of dimension +shape[0] x shape[1].
  4. +
  5. Copy constructor. Constructs a matrix with the dimensions and +contents of other.
  6. +
  7. Move constructor. Constructs a matrix with the dimensions and +contents of other using move semantics. After the move, +other is guaranteed to be empty.
  8. +
+

Parameters

+

shape - shape of the matrix to be constructed

+

other - another matrix to construct the new matrix +from

+

Complexity

+
    +
  1. Constant
  2. +
  3. Implementation defined
  4. +
  5. Implementation defined
  6. +
  7. Implementation defined
  8. +
+

Exceptions

+

Calls to Allocator::allocate may throw.

+

grb::matrix::~matrix

+
~matrix();
+

Destroys the grb::matrix. The destructors of the +elements are called and storage is deallocated.

+

Complexity

+

Linear in the size of the vector.

+

grb::matrix::operator=

+
matrix& operator=(const matrix& other);          (1)
+matrix& operator=(matrix&& other);               (2)
+

Replaces the matrix with the contents and shape of another +matrix.

+
    +
  1. Copy assignment operator. Modifies the shape of the matrix to be +equal to that of other and copies the stored values to be +the same as other.
  2. +
  3. Move constructor. Replaces the contents of the matrix with those of +other using move semantics. After the move assignment +operation completes, other is in a valid but indeterminate +state.
  4. +
+

Parameters

+

other - another matrix to assign the matrix to

+

Complexity

+
    +
  1. Implementation defined
  2. +
  3. Constant
  4. +
+

Exceptions

+
    +
  1. Calls to Allocator::allocate may throw.
  2. +
+

grb::matrix::size

+
size_type size() noexcept;
+

Returns the number of elements stored in the matrix.

+

Parameters

+

(none)

+

Return value

+

Number of stored elements.

+

Complexity

+

Constant

+

grb::matrix::max_size

+
size_type max_size() const noexcept;
+

Returns the maximum possible number of elements that could be stored +in the matrix due to system or implementation limitations.

+

Parameters

+

(none)

+

Return value

+

Maximum possible number of elements.

+

Complexity

+

Constant

+

grb::matrix::empty

+
bool empty() noexcept;
+

Returns whether the matrix is empty, that is where +size() == 0.

+

Parameters

+

(none)

+

Return value

+

Whether the matrix is empty.

+

Complexity

+

Constant

+

grb::matrix::shape

+
grb::index<I> shape() const noexcept;
+

Returns the dimensions of the matrix.

+

Parameters

+

(none)

+

Return value

+

Dimensions of the matrix.

+

Complexity

+

Constant

+

grb::matrix::begin +and grb::matrix::cbegin

+
iterator begin() noexcept;
+const_iterator begin() const noexcept;
+const_iterator cbegin() const noexcept;
+

Returns an iterator to the first element of the matrix data +structure. If the matrix is empty, returns an element that compares as +equal to end().

+

Parameters

+

(none)

+

Return value

+

Iterator to the first element

+

Complexity

+

Constant

+

grb::matrix::end +and grb::matrix::cend

+
iterator end() noexcept;
+const_iterator end() const noexcept;
+const_iterator cend() const noexcept;
+

Returns an iterator to one past the last element of the matrix data +structure. This element is used only to signify the end of the +container, and accessing it has undefined behavior.

+

Parameters

+

(none)

+

Return value

+

Iterator to one past the last element.

+

Complexity

+

Constant

+

grb::matrix::reshape

+
void reshape(grb::index<I> shape) noexcept;
+

Reshape the matrix. That is, modify the matrix dimensions such that +matrix shape is now shape[0] x shape[1]. If +any nonzeros lie outside of the new matrix shape, they are removed from +the matrix

+

Parameters

+

shape - New matrix shape

+

Return value

+

None

+

Complexity

+

Implementation defined

+

Exceptions

+

Calls to Allocator::allocate may throw.

+

grb::matrix::clear

+
void clear() noexcept;
+

Clear all stored scalar values from the matrix. The matrix maintains +the same shape, but after return will now have a size of 0.

+

Complexity

+

Implementation defined

+

grb::matrix::insert

+
template <typename InputIt>
+void insert(InputIt first, InputIt last);                    (1)
+std::pair<iterator, bool> insert(const value_type& value);   (2)
+std::pair<iterator, bool> insert(value_type&& value);        (3)
+

Inserts an element or number of elements into the matrix, if the +matrix doesn’t already contain a stored element at the corresponding +index.

+
    +
  1. Insert each element in the range [first, last) if an +element does not already exist in the matrix at the corresponding index. +If multiple elements in [first, last) have the same +indices, it is undefined which element is inserted.

  2. +
  3. and (3) Insert the element value if an element does +not already exist at the corresponding index in the matrix.

  4. +
+

Parameters

+

first, last - Range of elements to +insert

+

value - element to insert

+

Return value

+
    +
  1. None

  2. +
  3. and (3) return a std::pair containing an +iterator and a bool value. The +bool value indicates whether or not the insertion was +successful. If the insertion was successful, the first value contains an +iterator to the newly inserted element. If it was unsuccessful, it +contains an iterator to the element that prevented insertion.

  4. +
+

Complexity

+

Implementation defined

+

grb::matrix::insert_or_assign

+
template <class M>
+std::pair<iterator, bool> insert_or_assign(key_type k, M&& obj);
+

Inserts an element into index k in the matrix and +assigns to the scalar value if one already exists.

+

If an element already exists at index location k, +assigns std::forward<M>(obj) to the scalar value +stored at that index. If no element exists, inserts obj at +the index as if by calling insert with +value_type(k, std::forward<M>(obj)).

+

Parameters

+

k - the index location to assign obj

+

obj - the scalar value to be assigned

+

Type Requirements

+

M must fulfill +std::is_assignable<scalar_type&, M>

+

Return Value

+

Returns an std::pair with the first element holding an +iterator to the newly inserted or assigned value and the second element +holding a bool value that is true if the +element was inserted and false otherwise.

+

Complexity

+

Implementation defined.

+

grb::matrix::erase

+
size_type erase(grb::index<I> index);
+

Erases the element stored at index index if one +exists.

+

Parameters

+

index - the index of element to erase

+

Return Value

+

Returns the number of elements erased (0 or 1).

+

Complexity

+

Implementation defined.

+

grb::matrix::find

+
iterator find(grb::index<I> index);
+const_iterator find(grb::index<I> index) const;
+

Finds the element at location (index[0], +index[1]) in the matrix, returning an iterator to the +element. If no element is present at the location, returns +end().

+

Parameters

+

index - Location of the matrix element to find

+

Return value

+

An iterator pointing to the matrix element at the corresponding +index, or end() if there is no element at the location.

+

Complexity

+

Implementation defined

+

grb::matrix::operator[]

+
scalar_reference operator[](grb::index<I> index);
+const_scalar_reference operator[](grb::index<I> index) const;
+

Returns a reference to the scalar value stored at location +(index[0], index[1]) in the matrix. If no +value is stored at the location, inserts a default constructed value at +the location and returns a reference to it.

+

Parameters

+

index - Location of the matrix element

+

Return value

+

A reference to the scalar value at location (index[0], +[index[1]).

+

Complexity

+

Implementation defined

+

grb::matrix::at

+
scalar_reference at(grb::index<I> index);
+const_scalar_reference at(grb::index<I> index) const;
+

Returns a reference to the scalar value stored at location +(index[0], index[1]) in the matrix. If no +value is stored at the location, throws the exception +grb::out_of_range.

+

Parameters

+

index - Location of the matrix element

+

Return value

+

A reference to the scalar value at location (index[0], +[index[1]).

+

Complexity

+

Implementation defined

+

Exceptions

+

If no element exists at location (index[0], +index[1]), throws the exception +grb::out_of_range.

+

grb::vector

+
template <typename T,
+          std::integral I = std::size_t,
+          typename Hint = grb::sparse,
+          typename Allocator = std::allocator<T>>
+class grb::vector;
+

Template Parameters

+

T - type of scalar values stored in the vector

+

I - type, satisfying std::integral, used to +store indices in the vector

+

Hint - one or a composition of compile-time hints that +may be used to affect the backend storage type

+

Allocator - allocator type used to allocate memory

+

Member Types

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Member TypeDefinition
scalar_typeT, the type of scalar elements stored in the +vector
index_typeI, an integer type used to store vector indices
key_typeindex_type
map_typescalar_type
value_typegrb::vector_entry<T, I>, a tuple-like type +storing the indices and the stored element
size_typeA large unsigned integer type, usually std::size_t
difference_typeA large signed integer type, usually +std::ptrdiff_t
allocator_typeAllocator
iteratorAn iterator type fulfilling std::forward_iterator
const_iteratorA const iterator fulfilling std::forward_iterator
referencegrb::vector_ref<T, I>
const_referencegrb::vector_ref<const T, I>
scalar_referenceReference to scalar_type
const_scalar_referenceConst reference to scalar_type
hint_typeHint
+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
(constructor)Constructs vector
sizeNumber of stored elements in vector
max_sizeReturns the maximum possible number of elements
emptyReturn whether the vector is empty
shapeReturn the dimension of the vector
begin
cbegin
Returns iterator to beginning of container
end
cend
Returns iterator to one past last element in container
reshapeModify the dimension of the vector
clearClears all elements from the container
insertInsert elements
insert_or_assignInserts or assigns elements
findFinds an element
operator[]Access or insert element
+

grb::vector::vector

+
vector();                                           (1)
+vector(const Allocator& alloc);                     (2)
+vector(index_type shape);                           (3)
+vector(index_type shape, const Allocator& alloc);   (4)
+vector(const vector& other);                        (5)
+vector(vector&& other);                             (6)
+

Constructs new grb::vector data structure.

+
    +
  1. and 2) Constructs an empty vector of dimension 0.
  2. +
  3. and 4) Constructs an empty vector of dimension +shape.
  4. +
  5. Copy constructor
  6. +
  7. Move constructor
  8. +
+

Parameters

+

shape - shape of the vector to be constructed

+

Complexity

+
    +
  1. Constant
  2. +
  3. Implementation defined
  4. +
+

Exceptions

+

May throw std::bad_alloc.

+

grb::vector::size

+
size_type size() noexcept;
+

Returns the number of elements stored in the vector.

+

Parameters

+

(none)

+

Return value

+

Number of stored elements.

+

Complexity

+

Constant

+

grb::vector::max_size

+
size_type max_size() noexcept;
+

Returns the maximum possible number of elements that could be stored +in the vector due to platform or implementation limitations.

+

Parameters

+

(none)

+

Return value

+

Maximum possible number of elements.

+

Complexity

+

Constant

+

grb::vector::empty

+
bool empty() noexcept;
+

Returns whether the vector is empty, that is where +size() == 0.

+

Parameters

+

(none)

+

Return value

+

Whether the vector is empty.

+

Complexity

+

Constant

+

grb::vector::shape

+
index_type shape() const noexcept;
+

Returns the dimension of the vector.

+

Parameters

+

(none)

+

Return value

+

Dimension of the vector.

+

Complexity

+

Constant

+

grb::vector::begin +and grb::vector::cbegin

+
iterator begin() noexcept;
+const_iterator begin() const noexcept;
+const_iterator cbegin() const noexcept;
+

Returns an iterator to the first element of the vector data +structure. If the vector is empty, returns an element that compares as +equal to end().

+

Parameters

+

(none)

+

Return value

+

Iterator to the first element

+

Complexity

+

Constant

+

grb::vector::end +and grb::vector::cend

+
iterator end() noexcept;
+const_iterator end() const noexcept;
+const_iterator cend() const noexcept;
+

Returns an iterator to one past the last element of the vector data +structure. This element is used only to signify the end of the +container, and accessing it has undefined behavior.

+

Parameters

+

(none)

+

Return value

+

Iterator to one past the last element.

+

Complexity

+

Constant

+

grb::vector::reshape

+
void reshape(index_type shape);
+

Reshape the vector. That is, modify the vector dimension such that +vector is now of dimension shape. If any nonzeros lie +outside of the new vector shape, they are removed from the vector.

+

Parameters

+

shape - New vector shape

+

Return value

+

None

+

Complexity

+

Implementation defined

+

grb::vector::clear

+
void clear();
+

Clear all stored scalar values from the vector. The vector maintains +the same shape, but after return will now have a size of 0.

+

Complexity

+

Implementation defined

+

grb::vector::insert

+
template <typename InputIt>
+void insert(InputIt first, InputIt last);                    (1)
+std::pair<iterator, bool> insert(const value_type& value);   (2)
+std::pair<iterator, bool> insert(value_type&& value);        (3)
+

Inserts an element or number of elements into the vector, if the +vector doesn’t already contain a stored element at the corresponding +index.

+
    +
  1. Insert elements in the range [first, last) if an +element does not already exist in the vector at the corresponding index. +If multiple elements in [first, last) have the same +indices, it is undefined which element is inserted.

  2. +
  3. and (3) Insert the element value if an element does +not already exist at the corresponding index in the vector.

  4. +
+

Parameters

+

first, last - Range of elements to +insert

+

value - element to insert

+

Return value

+
    +
  1. None

  2. +
  3. and (3) return a std::pair containing an +iterator and a bool value. The +bool value indicates whether or not the insertion was +successful. If the insertion was successful, the first value contains an +iterator to the newly inserted element. If it was unsuccessful, it +contains an iterator to the element that prevented insertion.

  4. +
+

Complexity

+

Implementation defined

+

grb::vector::insert_or_assign

+
template <class M>
+std::pair<iterator, bool> insert_or_assign(key_type k, M&& obj);
+

Inserts an element into index k in the vector and +assigns to the scalar value if one already exists.

+

If an element already exists at index location k, +assigns std::forward<M>(obj) to the scalar value +stored at that index. If no element exists, inserts obj at +the index as if by calling insert with +value_type(k, std::forward<M>(obj)).

+

Parameters

+

k - the index location to assign obj

+

obj - the scalar value to be assigned

+

Type Requirements

+

M must fulfill +std::is_assignable<scalar_type&, M>

+

Return Value

+

Returns an std::pair with the first element holding an +iterator to the newly inserted or assigned value and the second element +holding a bool value that is true if the +element was inserted and false otherwise.

+

Complexity

+

Implementation defined.

+

grb::vector::erase

+
size_type erase(index_type index);
+

Erases the element stored at index index if one +exists.

+

Parameters

+

index - the index of the scalar value to erase

+

Return Value

+

Returns the number of elements erased (0 or 1).

+

Complexity

+

Implementation defined.

+

grb::vector::find

+
iterator find(index_type index);
+const_iterator find(index_type index) const;
+

Finds the element at location index in the vector, +returning an iterator to the element. If no element is present at the +location, returns end().

+

Parameters

+

index - Location of the vector element to find

+

Return value

+

An iterator pointing to the vector element at the corresponding +index, or end() if there is no element at the location.

+

Complexity

+

Implementation defined

+

grb::vector::operator[]

+
scalar_reference operator[](index_type index);
+const_scalar_reference operator[](index_type index) const;
+

Returns a reference to the scalar value stored at location +index in the vector. If no value is stored at the location, +inserts a default constructed value at the location and returns a +reference to it.

+

Parameters

+

index - Location of the vector element

+

Return value

+

A reference to the scalar value at location index.

+

Complexity

+

Implementation defined

+

grb::vector::at

+
scalar_reference at(index_type index);
+const_scalar_reference at(index_type index) const;
+

Returns a reference to the scalar value stored at location +index in the vector. If no value is stored at the location, +throws the exception grb::out_of_range.

+

Parameters

+

index - Location of the vector element

+

Return value

+

A reference to the scalar value at location index.

+

Complexity

+

Implementation defined

+

Exceptions

+

If no element exists at location index, throws the +exception grb::out_of_range.

+

grb::index

+
template <std::integral T>
+struct grb::index;
+

grb::index is a tuple-like type used to store matrix +indices and dimensions.

+

Template Parameters

+

T - type, satisfying std::integral, used to +store indices

+

Member Types

+ + + + + + + + + + + + + + + + + + + + + +
Member TypeDefinition
index_typeT
first_typeT
second_typeT
+

Member Objects

+ + + + + + + + + + + + + + + + + +
Member NameType
firstT
secondT
+

Methods

+ + + + + + + + + + + + + + + + + + + + + +
MethodDescription
(constructor)Constructs index
operator[]Get one of the indices
getGet one of the indices
+

Sparse Storage Format Hints

+

This section defines compile-time hints that can be used to direct +the storage format used to organize data inside GraphBLAS objects. +Storage hints can be used as optional template arguments to +grb::matrix, grb::vector, as well as some API +functions that return a matrix or vector. These compile-time hints +provide a mechanism for users to suggest to the GraphBLAS implementation +which storage format might be most appropriate for a particular matrix. +However, these compile-time hints are indeed hints to the +implementation and do not enforce any change in semantics to a matrix or +vector data structure and do not require it to use any particular +storage format. GraphBLAS implementations are encouraged to document +which storage formats they support, as well as how different hints will +affect which storage formats are used.

+

Example

+
#include <grb/grb.hpp>
+
+int main(int argc, char** argv) {
+  // Create a matrix with the `dense` compile-time hint.
+  // The implementation may choose to employ a dense storage format.
+  grb::matrix<float, std::size_t, grb::dense> x({10, 10});
+
+  // Create a matrix with the compile-time hint compose<sparse, row>.
+  // A GraphBLAS implementation may choose to employ a compressed sparse row
+  // storage format.
+  grb::matrix<float, std::size_t, grb::compose<grb::sparse, grb::row>> y({10, 10});
+
+
+  // No change in data structure semantics is implied by a hint.
+  x[{2, 3}] = 12;
+  x[{3, 6}] = 12;
+
+  y[{6, 7}] = 1;
+  y[{6, 7}] = 2.5;
+
+  grb::print(x);
+  grb::print(y);
+
+  return 0;
+}
+

grb::sparse

+
using sparse = /* undefined */;
+

Compile-time hint to suggest to the GraphBLAS implementation that a +sparse or compressed storage format is appropriate.

+

grb::dense

+
using dense = /* undefined */;
+

Compile-time hint to suggest to the GraphBLAS implementation that a +dense storage format is appropriate.

+

grb::row

+
using row = /* undefined */;
+

Compile-time hint to suggest to the GraphBLAS implementation that a +row-major storage format is appropriate.

+

grb::column

+
using column = /* undefined */;
+

Compile-time hint to suggest to the GraphBLAS implementation that a +column-major storage format is appropriate.

+

grb::compose

+
template <typename... Hints>
+using compose = /* undefined */;
+

Type alias used to combine multiple compile-time hints together.

+

Views

+

grb::views::transpose

+
namespace views {
+  inline constexpr /* unspecified */ transpose = /* unspecified */;
+}
+
Call signature
+
template <MatrixRange M>
+MatrixRange auto transpose(M&& matrix);
+

Parameters

+

matrix - a GraphBLAS matrix or matrix view

+

Type Requirements

+ +

Return Value

+

Returns a matrix view that is equal to the transpose of +matrix, satisfying MatrixRange.

+

If the value returned by transpose outlives the lifetime +of matrix, then the behavior is undefined.

+

grb::views::transform

+
namespace views {
+  inline constexpr /* unspecified */ transform = /* unspecified */;
+}
+
Call signature
+
template <MatrixRange M, std::copy_constructible Fn>
+MatrixRange auto transform (M&& matrix, Fn&& fn);             (1)
+
+template <VectorRange V, std::copy_constructible Fn>
+VectorRange auto transform(V&& vector, Fn&& fn);              (2)
+
    +
  1. fn must accept an argument of type +std::ranges::range_value_t<M> and return a value of +some type. The return type of fn will be the scalar type of +the transform view.

  2. +
  3. fn must accept an argument of type +std::ranges::range_value_t<V> and return a value of +some type. The return type of fn will be the scalar type of +the transform view.

  4. +
+

Parameters

+

matrix - a GraphBLAS matrix or matrix view satisfying +MatrixRange

+

vector - a GraphBLAS vector or vector view satisfying +VectorRange

+

fn - function used to transform matrix values +element-wise

+

Type Requirements

+ +

Return Value

+
    +
  1. Returns a view of matrix satisfying +MatrixRange. The stored scalar values will correspond to +every stored scalar value in matrix transformed using the +function fn.

  2. +
  3. Returns a view of vector satisfying +VectorRange. The stored scalar values will correspond to +every stored scalar value in vector transformed using the +function fn.

  4. +
+

Example

+
#include <grb/grb.hpp>
+
+int main(int argc, char** argv) {
+  grb::matrix<float> a({10, 10});
+
+  a[{1, 2}] = 12.0f;
+  a[{3, 4}] = 123.2f;
+  a[{7, 8}] = 8.0f;;
+
+  grb::print(a, "original matrix");
+
+  // Transform each scalar value based on its
+  // row and column index.
+  auto idx_view = grb::views::transform(a, [](auto&& entry) {
+                                              auto&& [idx, v] = entry;
+                                              auto&& [i, j] = idx;
+                                              return i + j;
+                                           });
+
+  grb::print(idx_view, "index transformed view");
+
+  return 0;
+}
+

grb::structure

+
template <MatrixRange M>
+grb::structure_view<M> structure(M&& matrix);                 (1) 
+
+template <VectorRange V>
+grb::structure_view<V> structure(V&& vector);                 (2)
+

Parameters

+

matrix - a GraphBLAS matrix or matrix view

+

vector - a GraphBLAS vector or vector view

+

Type Requirements

+ +

Return Value

+
    +
  1. Returns a view of the matrix
  2. +
+

Possible Implementation

+
inline constexpr bool always_true = [](auto&&) { return true; };
+
+template <typename O>
+using structure_view = grb::transform_view<O, decltype(always_true)>;
+
+template <MatrixRange M>
+grb::structure_view<M> structure(M&& matrix) {
+  return grb::transform(std::forward<M>(matrix), always_true);
+}
+
+template <VectorRange V>
+grb::structure_view<V> structure(V&& vector) {
+  return grb::transform(std::forward<V>(vector), always_true);
+}
+

grb::filter

+
template <MatrixRange M, typename Fn>
+grb::filter_view<M> filter(M&& matrix, Fn&& fn);              (1)
+
+template <VectorRange V, typename Fn>
+grb::filter_view<V> filter(V&& vector, Fn&& fn);              (2)
+

Parameters

+

matrix - a GraphBLAS matrix

+

vector - a GraphBLAS vector

+

fn - a function determining which elements should be +filtered out

+

Type Requirements

+ +

Return Value

+

Returns a filtered view of the matrix matrix or vector +vector. The return value fulfills the requirements of +MatrixRange (1) or VectorRange (2) . The +return value has the same shape as the input object, but without +elements for which fn(e) evaluates to false.

+

grb::complement

+
template <MaskMatrixRange M>
+grb::complement_view<M> complement(M&& mask);                 (1)
+
+template <MaskVectorRange V>
+grb::complement_view<V> complement(V&& mask);                 (2)
+

Parameters

+

mask - a GraphBLAS mask

+

Type Requirements

+ +

Return Value

+

TODO: Scott, Jose, is this the behavior we want? Returns the +complement view of a matrix or vector mask. At every index in +mask with no stored value or with a scalar value equal to +false when converted to bool, the returned +view has a stored value with the scalar value true. At +every stored value in mask with a scalar value equal to +true when converted to bool, the return view +has no stored value.

+
    +
  1. Returns a matrix view satisfying the requirements +MaskMatrixRange.

  2. +
  3. Returns a vector view satisfying the requirements +MaskVectorRange.

  4. +
+

grb::mask

+
template <MatrixRange Matrix, MaskMatrixRange M>
+grb::masked_view<Matrix, M> mask(Matrix&& matrix, M&& mask);                 (1)
+
+template <VectorRange Vector, MaskVectorRange M>
+grb::masked_view<Vector, M> mask(Vector&& vector, M&& mask);                 (2)
+

Parameters

+

matrix - a GraphBLAS matrix or vector

+

mask - a GraphBLAS mask with the same shape as +matrix (1) or vector (2)

+

Type Requirements

+ +

Return Value

+

Returns a view of the matrix matrix (1) or vector +vector that has been masked using mask. Any +value in matrix for which mask does not have +an entry at the corresponding location or for which mask +has a value equal to false when converted to +bool will not be visible in the returned mask view.

+
    +
  1. Returns a matrix view satisfying the requirements +MatrixRange. Any values in matrix for which +grb::find(mask, index) == grb::end(mask) || bool(*grb::find(mask, index)) == false +will be masked out of the returned matrix view.
  2. +
+

Exceptions

+

The exception grb::invalid_argument is thrown if the +mask does not have the same shape as matrix +(1) or vector (2).

+

grb::submatrix_view

+
template <MatrixRange M>
+grb::submatrix_view<M> submatrix(M&& matrix, grb::index<I> rows, grb::index<I> cols);
+

Parameters

+

matrix - a GraphBLAS matrix

+

rows - the span of rows in the submatrix view

+

cols - the span of columns in the submatrix view

+

Return Value

+

Returns a view of the submatrix of GraphBLAS matrix +matrix formed by the intersection of rows +rows[0] to rows[1] and columns +cols[0] to cols[1]. The returned matrix range +has shape +grb::min(rows[1], grb::shape(matrix)[0]) - grb::max(rows[0], 0) +by +grb::min(cols[1], grb::shape(matrix)[1]) - grb::max(cols[0], 0) +and contains all stored values for whose index the expression +index[0] >= rows[0] && index[0] < rows[1] && index[1] >= cols[0] && index[1] < cols[1] +holds true.

+

Exceptions

+

Returns the exception grb::invalid_argument if +rows[0] > rows[1] or +cols[0] > cols[1].

+

Pre-Defined Operators

+

The GraphBLAS C++ API defines a number of binary and unary operators. +Operators are defined as function objects and typically perform +arithmetic or logical operations like addition, multiplication, +negation, and logical and.

+

TODO: Discuss Unary Operators

+

They work the same way as binary operators, but are quite a bit +simpler, since there is only one value to operate upon.

+

Binary Operator Template +Parameters

+

GraphBLAS’s binary operators allow flexiblility in terms of whether +all, some, or none of the types are explicitly declared. If one or more +types are not explicitly declared, they are deduced at the callsite +where the operator is invoked. For each binary operator op, +there are three partial specializations defined:

+
    +
  1. op<T, U, V>, where the input arguments are +explicitly specified to be T and U and the +return value is V.
  2. +
  3. op<T, U, void>, where the input arguments are +explicitly specified to be T and U, and the +return value is deduced.
  4. +
  5. op<void, void, void>, where the inputs arguments +and return type are all deduced upon invocation.
  6. +
+

All binary operators have the following default template +parameters:

+
template <typename T = void, typename U = T, typename V = void>
+struct op;
+

This means the user can use a binary operator with zero, one, two, or +three template parameters explicitly specified. The types of the input +arguments and return value will be explicitly defined or reduced +accordingly.

+

No Types Specified

+

If a user specifies no template parameters when using a binary +operator, the result is a function object in which the input argument +and return value types are all deduced at the callsite.

+
#include <grb/grb.hpp>
+#include <iostream>
+int main(int argc, char** argv) {
+  // No types are explicitly specified.
+  // We can use this operator with values of
+  // any types for which an operator+() is defined.
+  grb::plus<> p1;
+  
+  std::size_t a = 1024;
+  std::uint8_t b = 12;
+  
+  // `std::size_t` and `std::uint8_t` deduced as types of input arguments.
+  // `std::size_t` will be deduced as type of return value.
+  // std::size_t + std::uint8_t -> std::size_t
+  auto c = p1(a, b);
+  
+  return 0;
+}
+

One Type Specified

+

If a user specifies one template parameters when using a binary +operator, the result is a function object in which the the two input +arguments are of the type specified, and the return value type is +deduced.

+
#include <grb/grb.hpp>
+#include <iostream>
+int main(int argc, char** argv) {
+  // Explicitly specify `int` as the type of both input values.
+  // Return value type will be deduced as `int`.
+  grb::plus<int> p1;
+  
+  int a = 1024;
+  int b = 12;
+  
+  // int + int -> int
+  int c = p1(a, b);
+  
+  return 0;
+}
+

Two Types Specified

+

If a user specifies two template parameters when using a binary +operator, the result is a function object in which the the two input +arguments are of the types specified, and the return value type is +deduced.

+
#include <grb/grb.hpp>
+#include <iostream>
+int main(int argc, char** argv) {
+  // Explicitly specify `std::size_t` for the lefthand argument
+  // and `std::uint8_t` for the righthand argument.
+  // Return value type will be deduced as `std::size_t`.
+  grb::plus<std::size_t, std::uint8_t> p1;
+  
+  std::size_t a = 1024;
+  std::uint8_t b = 12;
+  
+  // std::size_t + std::uint8_t -> std::size_t
+  std::size_t c = p1(a, b);
+  
+  return 0;
+}
+

Three Types Specified

+

If a user specifies all three template parameters when using a binary +operator, both of the input argument types as well as the return value +type of the function are explicitly specified.

+
#include <grb/grb.hpp>
+#include <iostream>
+int main(int argc, char** argv) {
+  // Explicitly specify `std::size_t` for the lefthand argument
+  // and `std::uint8_t` for the righthand argument.
+  // Return value type explicitly specified as `int`.
+  grb::plus<std::size_t, std::uint8_t, int> p1;
+  
+  std::size_t a = 1024;
+  std::uint8_t b = 12;
+  
+  // std::size_t + std::uint8_t -> std::size_t
+  std::size_t c =  p1(a, b);
+  
+  return 0;
+}
+

grb::plus

+
template <typename T = void, typename U = T, typename V = void>
+struct plus;
+

grb::plus is a binary operator. It forms a monoid on +arithmetic types.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
plus<void, void, void>deduces argument and return types
plus<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the sum of the two arguments
+

grb::plus::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the sum of lhs and rhs.

+

Parameters

+

lhs, rhs - values to sum

+

Return Value

+

The result of lhs + rhs.

+

Exceptions

+

May throw exceptions if the underlying operator+() +operation throws exceptions

+

Monoid Traits

+

grb::plus forms a monoid on any arithmetic type +A with the identity value 0, as long as +T, U, and V are equal to void or +A.

+

Specialization Details

+

grb::plus<void, void, void>

+
template <>
+struct plus<void, void, void>;
+

Version of grb::plus with both arguments and return +types deduced.

+

grb::plus::operator()

+
template <typename T, typename U>
+constexpr auto operator()(T&& lhs, U&& rhs) const
+  -> decltype(std::forward<T>(lhs) + std::forward<U>(rhs));
+

grb::plus<T, U, void>

+
template <typename T = void, typename U = T>
+struct plus<T, U, void>;
+

Version of grb::plus with explicit types for the +arguments, but return type deduced.

+

grb::plus::operator()

+
constexpr auto operator()(const T& lhs, const U& rhs) const
+  -> decltype(lhs + rhs);
+

grb::multiplies

+
template <typename T = void, typename U = T, typename V = void>
+struct multiplies;
+

grb::multiplies is a binary operator. It forms a monoid +on arithmetic types.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
multiplies<void, void, void>deduces argument and return types
multiplies<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the product of the two arguments
+

grb::multiplies::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the product of lhs and rhs.

+

Parameters

+

lhs, rhs - values to multiply

+

Return Value

+

The result of lhs * rhs.

+

Exceptions

+

May throw exceptions if the underlying operator*() +operation throws exceptions

+

Monoid Traits

+

grb::multiplies forms a monoid on any arithmetic type +A with the identity value 1, as long as +T, U, and V are equal to void or +A.

+

Specialization Details

+
grb::multiplies<void, void, void>
+
template <>
+struct multiplies<void, void, void>;
+

Version of grb::multiplies with both arguments and +return types deduced.

+
grb::multiplies::operator()
+
template <typename T, typename U>
+constexpr auto operator()(T&& lhs, U&& rhs) const
+  -> decltype(std::forward<T>(lhs) * std::forward<U>(rhs));
+
grb::multiplies<T, U, void>
+
template <typename T = void, typename U = T>
+struct multiplies<T, U, void>;
+

Version of grb::multiplies with explicit types for the +arguments, but return type deduced.

+
grb::multiplies::operator()
+
constexpr auto operator()(const T& lhs, const U& rhs) const
+  -> decltype(lhs * rhs);
+

grb::minus

+
template <typename T = void, typename U = T, typename V = void>
+struct minus;
+

grb::minus is a binary operator that subtracts two +values.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
minus<void, void, void>deduces argument and return types
minus<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the difference of the two arguments
+

grb::minus::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the difference of lhs and rhs.

+

Parameters

+

lhs, rhs - values to subtract

+

Return Value

+

The result of lhs - rhs.

+

Exceptions

+

May throw exceptions if the underlying operator-() +operation throws exceptions

+

Monoid Traits

+

grb::minus does not form a monoid for arithmetic +types.

+

Specialization Details

+

grb::minus<void, void, void>

+
template <>
+struct minus<void, void, void>;
+

Version of grb::minus with both arguments and return +types deduced.

+

grb::minus::operator()

+
template <typename T, typename U>
+constexpr auto operator()(T&& lhs, U&& rhs) const
+  -> decltype(std::forward<T>(lhs) - std::forward<U>(rhs));
+

grb::minus<T, U, void>

+
template <typename T = void, typename U = T>
+struct minus<T, U, void>;
+

Version of grb::minus with explicit types for the +arguments, but return type deduced.

+

grb::minus::operator()

+
constexpr auto operator()(const T& lhs, const U& rhs) const
+  -> decltype(lhs - rhs);
+

grb::divides

+
template <typename T = void, typename U = T, typename V = void>
+struct divides;
+

grb::divides is a binary operator that divides two +values.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
divides<void, void, void>deduces argument and return types
divides<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the difference of the two arguments
+

grb::divides::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the difference of lhs and rhs.

+

Parameters

+

lhs, rhs - values to divide

+

Return Value

+

The result of lhs / rhs.

+

Exceptions

+

May throw exceptions if the underlying operator/() +operation throws exceptions

+

Monoid Traits

+

grb::divides does not form a monoid for arithmetic +types.

+

Specialization Details

+

grb::divides<void, void, void>

+
template <>
+struct divides<void, void, void>;
+

Version of grb::divides with both arguments and return +types deduced.

+

grb::divides::operator()

+
template <typename T, typename U>
+constexpr auto operator()(T&& lhs, U&& rhs) const
+  -> decltype(std::forward<T>(lhs) / std::forward<U>(rhs));
+

grb::divides<T, U, void>

+
template <typename T = void, typename U = T>
+struct divides<T, U, void>;
+

Version of grb::divides with explicit types for the +arguments, but return type deduced.

+
grb::divides::operator()
+
constexpr auto operator()(const T& lhs, const U& rhs) const
+  -> decltype(lhs / rhs);
+

grb::max

+
template <typename T = void, typename U = T, typename V = void>
+struct max;
+

grb::max is a binary operator that returns the larger of +two arguments. When both input arguments have integral types, +std::cmp_less is used for comparison. When one or both +arguments have non-integral types, operator< is used for +comparison. It forms a monoid on arithmetic types.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
max<void, void, void>deduces argument and return types
max<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the larger of two arguments
+

grb::max::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the larger of lhs and rhs.

+

Parameters

+

lhs, rhs - values to take the max of

+

Return Value

+

The larger of lhs and rhs.

+

Exceptions

+

May throw exceptions if the underlying operator<() +operation throws exceptions

+

Monoid Traits

+

grb::max forms a monoid on any arithmetic type +A with the identity value +std::min(std::numeric_limits<A>::lowest(), -std::numeric_limits<A>::infinity()), +as long as T, U, and V are equal +to void or A.

+

Specialization Details

+

grb::max<void, void, void>

+
template <>
+struct max<void, void, void>;
+

Version of grb::max with both arguments and return types +deduced.

+

grb::max::operator()

+
template <std::integral T, std::integral U>
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+      std::cmp_less(std::numeric_limits<T>::max(),
+                    std::numeric_limits<U>::max()),
+      U, T
+     >;
+
+template <typename T, typename U>
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+      std::numeric_limits<T>::max() < std::numeric_limits<U>::max(),
+      U, T
+     >
+requires(!(std::is_integral_v<T> && std::is_integral_v<U>));
+

grb::max<T, U, void>

+
template <typename T = void, typename U = T>
+struct max<T, U, void>;
+

Version of grb::max with explicit types for the +arguments, but return type deduced.

+

grb::max::operator()

+
constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+      std::cmp_less(std::numeric_limits<T>::max(),
+                    std::numeric_limits<U>::max()),
+      U, T
+     >;
+
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+      std::numeric_limits<T>::max() < std::numeric_limits<U>::max(),
+      U, T
+     >
+requires(!(std::is_integral_v<T> && std::is_integral_v<U>));
+

grb::min

+
template <typename T = void, typename U = T, typename V = void>
+struct min;
+

grb::min is a binary operator that returns the smaller +of two arguments. using operator< for comparison. When +both input arguments have integral types, std::cmp_less is +used for comparison. When one or both arguments have non-integral types, +operator< is used for comparison. It forms a monoid on +arithmetic types.

+

Specializations

+ + + + + + + + + + + + + + + + + +
SpecializationDescription
min<void, void, void>deduces argument and return types
min<T, U, void>deduces return type based on T and U
+

Template Parameters

+

T - Type of the left hand argument of the operator

+

U - Type of the right hand argument of the operator

+

V - Return type of the operator

+

Methods

+ + + + + + + + + + + + + +
MethodDescription
operator()returns the smaller of two arguments
+

grb::min::operator()

+
constexpr V operator()( const T& lhs, const U& rhs ) const;
+

Returns the smaller of lhs and rhs.

+

Parameters

+

lhs, rhs - values to take the min of

+

Return Value

+

The smaller of lhs and rhs.

+

Exceptions

+

May throw exceptions if the underlying operator<() +operation throws exceptions

+

Monoid Traits

+

grb::min forms a monoid on any arithmetic type +A with the identity value +std::max(std::numeric_limits<A>::max(), std::numeric_limits<A>::infinity()), +as long as T, U, and V are equal +to void or A.

+

Specialization Details

+

grb::min<void, void, void>

+
template <>
+struct min<void, void, void>;
+

Version of grb::min with both arguments and return types +deduced.

+

grb::min::operator()

+
template <std::integral T, std::integral U>
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+       std::cmp_less(std::numeric_limits<U>::lowest(),
+                     std::numeric_limits<T>::lowest()),
+       U, T
+     >;
+
+template <typename T, typename U>
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+       std::numeric_limits<U>::lowest() < std::numeric_limits<T>::lowest(),
+       U, T
+     >
+requires(!(std::is_integral_v<T> && std::is_integral_v<U>));
+

grb::min<T, U, void>

+
template <typename T = void, typename U = T>
+struct min<T, U, void>;
+

Version of grb::min with explicit types for the +arguments, but return type deduced.

+

grb::min::operator()

+
constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+       std::cmp_less(std::numeric_limits<U>::lowest(),
+                     std::numeric_limits<T>::lowest()),
+       U, T
+     >;
+
+constexpr auto operator()(const T& a, const U& b) const
+  -> std::conditional_t<
+       std::numeric_limits<U>::lowest() < std::numeric_limits<T>::lowest(),
+       U, T
+     >
+requires(!(std::is_integral_v<T> && std::is_integral_v<U>));
+

Utilities

+

TODO: need “disablers” for all these CPOs. Also, “converted to +its decayed type?”

+

grb::get

+
inline constexpr /* unspecified */ get = /* unspecified */;
+

Call Signature

+
template <std::size_t I, typename T>
+requires /* see below */
+constexpr std::tuple_element<I, T> get(T&& tuple);
+

TODO: we need someone who understands CPOs a little better to +understand this.

+

Returns the I'th element stored in the tuple-like object +tuple.

+

A call to grb::get is expression-equivalent to:

+
    +
  1. tuple.get<I>(), if that expression is valid.
  2. +
  3. Otherwise, any calls to get(tuple) found through +argument-dependent lookup.
  4. +
  5. Otherwise, std::get<I>(tuple).
  6. +
+

In all other cases, a call to grb::get is +ill-formed.

+

grb::size

+
template <typename T>
+inline constexpr /* unspecified */ size = std::ranges::size;
+

Call Signature

+
template <typename T>
+constexpr auto size(T&& t);
+

Returns the number of stored values in a GraphBLAS matrix, vector, or +other range. Whenever grb::size(e) is valid for an +expression e, the return type is integer-like.

+

A call to grb::size(t) is expression-equivalent to:

+
    +
  1. t.size(), if that expression is valid.
  2. +
  3. Otherwise, any calls to size(t), found through +argument-dependent lookup.
  4. +
+

In all other cases, a call to grb::size is +ill-formed.

+

grb::shape

+
template <typename T>
+inline constexpr /* unspecified */ shape = /* unspecified */;
+

Call Signature

+
template <typename T>
+requires /* see below */
+constexpr auto shape(T&& t);
+

Returns the shape of a GraphBLAS object. If T fulfills +the requirements of MatrixRange, then the return type will +be a tuple-like type storing two integer-like values, fulfilling the +requirements of TupleLike<I, I>, where I +is the index type of T. If T fulfills the +requirements of VectorRange, then the return type will be +I, where I is the index type of +T.

+

A call to grb::shape is expression-equivalent to:

+
    +
  1. t.shape() if that expression is valid.
  2. +
  3. Otherwise, shape(t), if that expression is valid, +including any declarations of shape found through +argument-dependent lookup.
  4. +
+

In all other cases, a call to grb::shape is +ill-formed.

+

grb::find

+
template <typename T>
+inline constexpr /* unspecified */ find = /* unspecified */;
+

Call Signature

+
template <typename R, typename T>
+requires /* see below */
+constexpr auto find(R&& r, T&& t);
+

Return an iterator to the stored value in the GraphBLAS matrix or +vector r at index location t.

+

A call to grb::find is expression-equivalent to:

+
    +
  1. r.find(t) if that expression is valid.
  2. +
  3. Otherwise, any calls to find(r, t) found through +argument-dependent lookup.
  4. +
  5. Otherwise, any calls to std::find(r, t), if that +expression is valid.
  6. +
+

In all other cases, a call to grb::find is +ill-formed.

+

grb::insert

+
template <typename T>
+inline constexpr /* unspecified */ insert = /* unspecified */;
+

Call Signature

+
template <typename R, typename T>
+requires /* see below */
+constexpr auto insert(R&& r, T&& t);
+

Attempt to insert the value t into the GraphBLAS matrix +or vector r.

+

A call to grb::insert is expression-equivalent to:

+
    +
  1. r.insert(t) if that expression is valid.
  2. +
  3. Otherwise, any calls to insert(r, t) found through +argument-dependent lookup.
  4. +
+

scalar_result_type_t

+
template <typename A, typename B, typename Combine>
+using scalar_result_type_t = std::declval<Combine>()(
+                                std::declval<scalar_type_t<A>>(),
+                                std::declval<scalar_type_t<B>>());
+

The type of the scalar elements produced by combining GraphBLAS +objects of type A and B elementwise using a +binary operator of type Combine.

+

multiply_result_t

+
template <typename A, typename B, typename Reduce, typename Combine, typename Mask>
+using multiply_result_t = /* undefined */;
+

The type returned when multiply is called on GraphBLAS matrix or +vector ranges of type A and B using binary +operators Reduce and Combine with mask +Mask.

+

The scalar type of the returned matrix will be +combine_result_t<A, B, Combine>, and the index type +will be grb::container_index_t<A> or +grb::container_index_t<B>, whichever is able to store +the larger value.

+

combine_result_t

+
template <typename A, typename B, typename Combine>
+using combine_result_t = std::invoke_result_t<Combine, A, B>;
+

The type returned when the binary operator Combine is +called with an element of the scalar type of A as the first +argument and an element of the scalar type of B as the +second argument. A and B must be GraphBLAS +matrix or vector objects.

+

ewise_union_result_t

+
template <typename A, typename B, typename Combine, typename Mask>
+using ewise_union_result_t = /* undefined */;
+

The type returned when ewise_union is called on the +GraphBLAS matrix or vector ranges of type A and +B using the binary operator Combine.

+

ewise_intersection_result_t

+
template <typename A, typename B, typename Combine, typename Mask>
+using ewise_intersection_result_t = /* undefined */;
+

The type returned when ewise_intersection is called on +the GraphBLAS matrix or vector ranges of type A and +B using the binary operator Combine.

+

read_matrix

+

+template <typename T,
+          std::integral I = std::size_t,
+          typename Hint = grb::sparse,
+          typename Allocator = std::allocator<T>>
+grb::matrix<T, I, Hint, Allocator>
+read_matrix(std::string file_path);
+

Constructs a new GraphBLAS matrix based on the contents of a +file.

+

Template Parameters

+

T - type of scalar values stored in matrix

+

I - type of matrix indices

+

Hint - compile-time hint for backend storage format.

+

Allocator - allocator type

+

Parameters

+

file_path - string holding the file path of the matrix +to be read

+

Return Value

+

Returns a GraphBLAS matrix whose dimensions and contents correspond +to the file located at file_path.

+

Complexity

+

Complexity is implementation-defined.

+

Exceptions

+ +

Notes

+

GraphBLAS implementations must define the file formats that they +support. Implementations are strongly encouraged to support the +MatrixMarket format.

+

Example

+

Concepts

+

Binary Operator

+

Binary operators are function objects that are invocable with two +arguments, returning a single value. Binary operators can be callables +defined by a GraphBLAS library, the C++ Standard Library, or application +developers. Binary operators may be callable with a variety of different +types, or only with elements of a single type. We say a binary operator +is valid for a particular operation T x U -> V if it is +callable with arguments of type T and U and +returns a value convertible to type V.

+

Requirements

+
    +
  1. Callable of type Fn can be invoked with two arguments +of type T and U.
  2. +
  3. The return value is convertible to type V.
  4. +
+

Concept

+
template <typename Fn, typename T, typename U = T, typename V = grb::any>
+concept BinaryOperator = requires(Fn fn, T t, U u) {
+                           {fn(t, u)} -> std::convertible_to<V>;
+                         };
+

Remarks

+

The last two arguments are defaulted unless explicit template +parameters are provided. The second parameter to the concept, +U, which is the right-hand side input to the binary +operator, defaults to T. The final parameter, +V, which represents the output of the binary operator, +defaults to grb::any, meaning that the return value may +have any type.

+

Example

+
// Constrain `Fn` to require a binary operator that accepts two integers
+// as arguments and returns a value of any type.
+template <BinaryOperator<int> Fn>
+auto apply(Fn&& fn, int a, int b) {
+  return fn(a, b);
+}
+
+// The following code will result in an error, since the function passed
+// does not fulfill the BinaryOperator<int> requirement, as it cannot accept
+// integers.
+void test() {
+  auto fn = [](std::string a, std::string b) { return a.size() + b.size(); };
+  apply(fn, 12, 13);
+}
+

Monoid

+

GraphBLAS monoids are commutative monoids. Throughout this +specification, they are referred to simply as monoids. They are binary +operators that have special properties when applied to elements of some +type T. We say that a function object Fn forms +on a monoid on type T if the following requirements are +met.

+

Requirements

+
    +
  1. Callable of type Fn fulfills the concept +BinaryOperator<T, T, T> for some type +T.
  2. +
  3. The operation is associative and commutative for type +T.
  4. +
  5. The operation has an identity element for type T, +accessible using +grb::monoid_traits<Fn, T>::identity().
  6. +
+

Concept

+
template <typename Fn, typename T>
+concept Monoid = BinaryOperator<Fn, T, T, T> &&
+                 requires { {grb::monoid_traits<Fn, T>::identity()} -> std::same_as<T>; };
+

Tuple-Like Type

+

Tuple-like types are types that, similar to instantiations of +std::tuple or std::pair, store multiple +values. The number of values stored in the tuple-like type, as well as +the type of each value, are known at compile time. We say that a type +T is tuple-like for the parameter pack of types +Types if it fulfills the following requirements.

+

Requirements

+
    +
  1. The tuple T has a size accessible using template +std::tuple_size whose type is equal to +std::size_t and whose value is equal to +sizeof...(Types).
  2. +
  3. The type of each stored value in the tuple T is +accessible using std::tuple_element, with the N’th stored +value equal to the N’th type in Types.
  4. +
  5. Each stored value in T is accessible using the +customization point object grb::get, which will invoke +either the method get() if it is present in the tuple type +T or std::get(). The type of the return value +for the N’th element must be convertible to the N’th element of +Types.
  6. +
+

Concept

+

_TODO: this concept could refactored to be a bit more elegant.

+
template <typename T, std::size_t I, typename U = grb::any>
+concept TupleElementGettable = requires(T tuple) {
+                                 {grb::get<I>(tuple)} -> std::convertible_to<U>;
+                               };
+template <typename T, typename... Args>
+concept TupleLike =
+  requires {
+    typename std::tuple_size<std::remove_cvref_t<T>>::type;
+    requires std::same_as<std::remove_cvref_t<decltype(std::tuple_size_v<std::remove_cvref_t<T>>)>, std::size_t>;
+  } &&
+  sizeof...(Args) == std::tuple_size_v<std::remove_cvref_t<T>> &&
+  []<std::size_t... I>(std::index_sequence<I...>) {
+    return (TupleElementGettable<T, I, Args> && ...);
+  }(std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<T>>>());
+

Example

+
// The Concept `TupleLike<int, int, float>` constraints `T`
+// to be a tuple-like type storing int, int, float.
+template<TupleLike<int, int, float> T>
+void print_tuple(T&& tuple) {
+  auto&& [i, j, v] = tuple;
+  printf("%d, %d, %f\n", i, j, v);
+}
+

Matrix Entry

+

Matrix entries represent entries in a GraphBLAS matrix, which include +both a tuple-like index storing the row and column index of the stored +scalar value, as well as the scalar value itself. We say that a type +Entry is a valid matrix entry for the scalar type +T and index type I if the following +requirements are met.

+

Requirements

+
    +
  1. Entry is a tuple-like type with a size of 2.
  2. +
  3. The first element stored in the tuple-like type Entry +is a tuple-like type fulfilling TupleLike<I, I>, +storing the row and column index of the matrix entry.
  4. +
  5. The second element stored in the tuple-like type Entry +holds the matrix entry’s scalar value, and is convertible to +T.
  6. +
+

Concept

+
template <typename Entry, typename T, typename I>
+concept MatrixEntry = TupleLike<Entry, grb::any, grb::any> &&
+                      requires(Entry entry) { {grb::get<0>(entry)} -> TupleLike<I, I>; } &&
+                      requires(Entry entry) { {grb::get<1>(entry)} -> std::convertible_to<T>; };
+

Mutable Matrix Entry

+

A mutable matrix entry is an entry in a matrix that fulfills all the +requirements of matrix entry, but whose stored scalar value can be +mutated by assigning to some value of type U. We say that a +matrix entry Entry is a mutable matrix entry for scalar +type T, index type I, and output type +U, if it fulfills all the requirements of matrix entry as +well as the following requirements.

+

Requirements

+
    +
  1. The second element of the tuple Entry, representing the +scalar value, is assignable to elements of type U.
  2. +
+

Concept

+
template <typename Entry, typename T, typename I, typename U>
+concept MutableMatrixEntry = MatrixEntry<Entry, T, I> &&
+                             std::is_assignable_v<decltype(std::get<1>(std::declval<Entry>())), U>;
+

Matrix Range

+

A matrix in GraphBLAS consists of a range of values distributed over +a two-dimensional domain. In addition to grb::matrix, which directly stores +a collection of values, there are other types, such as views, that +fulfill the same interface. We say that a type M is a +matrix range if the following requirements are met.

+

Requirements

+
    +
  1. M has a scalar type of the stored values, accessible +with grb::matrix_scalar_t<M>
  2. +
  3. M has an index type used to reference the indices of +the stored values, accessible with +grb::matrix_index_t<M>.
  4. +
  5. M is a range with a value type that represents a matrix +tuple, containing both the index and scalar value for each stored +value.
  6. +
  7. M has a shape, which is a tuple-like object of size +two, holding the number of rows and the number of columns, accessible by +invoking the method shape() on an object of type +M.
  8. +
  9. M has a method find() that takes an index +tuple and returns an iterator.
  10. +
+

Concept

+
template <typename M>
+concept MatrixRange = std::ranges::sized_range<M> &&
+  requires(M matrix) {
+    typename grb::matrix_scalar_t<M>;
+    typename grb::matrix_index_t<M>;
+    {std::declval<std::ranges::range_value_t<std::remove_cvref_t<M>>>()}
+      -> MatrixEntry<grb::matrix_scalar_t<M>,
+                     grb::matrix_index_t<M>>;
+    {grb::shape(matrix)} -> Tuplelike<grb::matrix_index_t<M>,
+                                  grb::matrix_index_t<M>>;
+    {grb::find(matrix, {grb::matrix_index_t<M>{}, grb::matrix_index_t<M>{}})}
+                 -> std::convertible_to<std::ranges::iterator_t<M>>;
+  };
+

Mutable Matrix Range

+

Some matrices and matrix-like objects are mutable, meaning +that their stored values may be modified. Examples of mutable matrix +ranges include instantiations of grb::matrix and certain +matrix views that allow adding new values and modifying old values, such +as grb::transpose. We say that a type M is a +mutable matrix range for the scalar value T if the +following requirements are met.

+

Requirements

+
    +
  1. M is a matrix range.
  2. +
  3. The value type of M fulfills the requirements of +MutableMatrixEntry<T, I>.
  4. +
  5. M has a method insert() that takes a +matrix entry tuple and attempts to insert the element into the matrix, +returning an iterator to the new element on success and returning an +iterator to the end on failure.
  6. +
+

Concept

+
template <typename M, typename T>
+concept MutableMatrixRange = MatrixRange<M> &&
+                             MutableMatrixEntry<std::ranges::range_value_t<M>
+                                                grb::matrix_scalar_t<M>,
+                                                grb::matrix_index_t<M>,
+                                                T> &&
+  requires(M matrix, T value) {
+    {grb::insert(matrix, {{grb::matrix_index_t<M>{}, grb::matrix_index_t<M>{}},
+                          value}) -> std::ranges::iterator_t<M>;
+    }
+  };
+

Mask Matrix Range

+

Some operations require masks, which can be used to avoid computing +and storing certain parts of the output. We say that a type +M is a mask matrix range if the following requirements are +met.

+

Requirements

+
    +
  1. M is a matrix range.
  2. +
  3. The scalar value type of M is convertible to +bool.
  4. +
+

Concept

+
template <typename M>
+concept MaskMatrixRange = MatrixRange<M> &&
+                          std::is_convertible_v<grb::matrix_scalar_t<M>, bool>;
+

Vector Entry

+

Vector entries represent entries in a GraphBLAS vector, which include +both an std::integral index storing the index of the stored +scalar value, as well as the scalar value itself. We say that a type +Entry is a valid matrix entry for the scalar type +T and index type I if the following +requirements are met.

+

Requirements

+
    +
  1. Entry is a tuple-like type with a size of 2.
  2. +
  3. The first element stored in the tuple-like type Entry +fulfills std::integral.
  4. +
  5. The second element stored in the tuple-like type Entry +holds the vector’s scalar value, and is convertible to +T.
  6. +
+

Concept

+
template <typename Entry, typename T, typename I>
+concept VectorEntry = TupleLike<Entry, grb::any, grb::any> &&
+                      requires(Entry entry) { {grb::get<0>(entry)} -> std::integral; } &&
+                      requires(Entry entry) { {grb::get<1>(entry)} -> std::convertible_to<T>; };
+

Mutable Vector Entry

+

A mutable vector entry is an entry in a vector that fulfills all the +requirements of vector entry, but whose stored scalar value can be +mutated by assigning to some value of type U. We say that a +vector entry Entry is a mutable vector entry for scalar +type T, index type I, and output type +U, if it fulfills all the requirements of vector entry as +well as the following requirements.

+

Requirements

+
    +
  1. The second element of the tuple Entry, representing the +scalar value, is assignable to elements of type U.
  2. +
+

Concept

+
template <typename Entry, typename T, typename I, typename U>
+concept MutableVectorEntry = VectorEntry<Entry, T, I> &&
+                             std::is_assignable_v<decltype(std::get<1>(std::declval<Entry>())), U>;
+

Vector Range

+

A vector in GraphBLAS consists of a range of values distributed over +a one-dimensional domain. In addition to grb::vector, which directly stores +a collection of values, there are other types, such as views, that +fulfill the same interface. We say that a type V is a +vector range if the following requirements are met.

+

TODO: make requirements list find CPO, not method.

+

Requirements

+
    +
  1. V has a scalar type of the stored values, accessible +with grb::vector_scalar_t<V>
  2. +
  3. V has an index type used to reference the indices of +the stored values, accessible with +grb::vector_index_t<V>.
  4. +
  5. V is a range with a value type that represents a vector +tuple, containing both the index and scalar value for each stored +value.
  6. +
  7. V has a shape, which is an integer-like object, holding +the dimension of the vector, accessible by invoking the method +shape() on an object of type V.
  8. +
  9. V has a method find() that takes an index +and returns an iterator.
  10. +
+

Concept

+

TODO: this is a bit sketchy, and needs to have some of the +components fleshed out.

+
template <typename M>
+concept VectorRange = std::ranges::sized_range<V> &&
+  requires(V vector) {
+    typename grb::vector_scalar_t<V>;
+    typename grb::vector_index_t<V>;
+    {std::declval<std::ranges::range_value_t<std::remove_cvref_t<V>>>()}
+      -> VectorEntry<grb::vector_scalar_t<V>,
+                     grb::vector_index_t<V>>;
+    {grb::shape(vector)} -> std::same_as<grb::vector_index_t<V>>;
+    {grb::find(vector, grb::vector_index_t<V>)} -> std::convertible_to<std::ranges::iterator_t<V>>;
+  };
+

Mutable Vector Range

+

Some vectors and vector-like objects are mutable, meaning +that their stored values may be modified. Examples of mutable vector +ranges include instantiations of grb::vector and certain +vector views that allow adding new values and modifying old values, such +as grb::transpose. We say that a type V is a +mutable vector range for the scalar value T if the +following requirements are met.

+

Requirements

+
    +
  1. V is a vector range.
  2. +
  3. The value type of M fulfills the requirements of +MutableVectorEntry<T, I>.
  4. +
  5. M has a method insert() that takes a +vector entry tuple and attempts to insert the element into the vector +returning an iterator to the new element on success and returning an +iterator to the end on failure.
  6. +
+

Concept

+
template <typename V, typename T>
+concept MutableVectorRange = VectorRange<V> &&
+                             MutableVectorEntry<std::ranges::range_value_t<V>,
+                                                grb::vector_scalar_t<V>,
+                                                grb::vector_index_t<V>,
+                                                T> &&
+  requires(V vector, T value) {
+    {grb::insert(vector, {grb::vector_index_t<V>{}, value})}
+      -> std::same_as<std::ranges::iterator_t<V>>;
+  };
+

Mask Vector Range

+

Some operations require masks, which can be used to avoid computing +and storing certain parts of the output. We say that a type +M is a mask vector range if the following requirements are +met.

+

Requirements

+
    +
  1. M is a vector range.
  2. +
  3. The scalar value type of M is convertible to +bool.
  4. +
+

Concept

+
template <typename M>
+concept MaskVectorRange = VectorRange<M> &&
+                          std::is_convertible_v<grb::vector_scalar_t<M>, bool>;
+

Type Traits

+

grb::monoid_traits

+
template <typename Fn, typename T>
+struct monoid_traits;
+

The monoid_traits template struct provides information +about the monoid that is formed by the commutative binary operator +Fn on the type T. Namely, it provides a way to +retrieve the monoid’s identity.

+

Users can specialize monoid_traits for custom operators, +which will make their identity elements available to GraphBLAS +algorithms, possibly enabling optimizations. The default specialization +of monoid_traits detects and provides the identity of the +monoid if it has an identity method.

+

Template Parameters

+

Fn - type of commutative binary operator

+

T - type on which Fn forms a commutative +monoid

+

Member Types

+ + + + + + + + + + + + + + + +
Member TypeDefinitionDescription
typeTtype of the monoid
+

The default specialization has the following member functions:

+

Member Functions

+ + + + + + + + + + + + + + + +
FunctionDescription
identitythe identity value of the monoid
+

grb::monoid_traits<Fn, T>::identity

+
static constexpr T identity() noexcept;
+

Returns the identity of the monoid.

+

Parameters

+

None

+

Complexity

+

Constant

+

Exceptions

+

May not throw exceptions

+

Possible Implementation

+
template <typename Fn, typename T>
+static constexpr T grb::monoid_traits<Fn, T>::identity() noexcept {
+  if constexpr(requires { {Fn::identity() } -> std::same_as<T> }) {
+    return Fn::identity();
+  } else if constexpr(requires { {Fn:: template identity<T>()} -> std::same_as<T> }) {
+    return Fn:: template identity<T>();
+  }
+}
+

Specializations

+
template <std::arithmetic T>
+struct grb::monoid_traits<std::plus<T>, T>;
+
+template <std::arithmetic T>
+struct grb::monoid_traits<std::plus<void>, T>;
+
template <std::arithmetic T>
+struct grb::monoid_traits<std::multiplies<T>, T>;
+
+template <std::arithmetic T>
+struct grb::monoid_traits<std::multiplies<void>, T>;
+

grb::matrix_value_t

+
template <typename Matrix>
+using matrix_value_t = std::ranges::range_value_t<Matrix>;
+

Obtain the value type of the matrix-like type Matrix. +Equal to std::ranges::range_value_t<Matrix>.

+

grb::vector_value_t

+
template <typename Vector>
+using vector_value_t = std::ranges::range_value_t<Vector>;
+

Obtain the value type of the vector-like type Vector. +Equal to std::ranges::range_value_t<Vector>.

+

grb::matrix_scalar_t

+
template <typename Matrix>
+using matrix_scalar_t = std::remove_cvref_t<typename std::tuple_element<1, matrix_value_t<Matrix>>::type>;
+

Obtain the type of scalar values stored in the matrix-like type +Matrix. Equal to the second element stored in the matrix’s +tuple-like value type.

+

grb::vector_scalar_t

+
template <typename Vector>
+using vector_scalar_t = std::remove_cvref_t<typename std::tuple_element<1, vector_value_t<Vector>>::type>;
+

Obtain the type of scalar values stored in the vector-like type +Vector. Equal to the second element stored in the vector’s +tuple-like value type.

+

grb::matrix_key_t

+
template <typename Matrix>
+using matrix_key_t = std::remove_cvref_t<typename std::tuple_element<0, matrix_value_t<Matrix>>::type>;
+

Obtain the key type of the matrix. This is a tuple-like type used to +store each scalar value’s row and column indices.

+

grb::matrix_index_t

+
template <typename Matrix>
+using matrix_index_t = std::remove_cvref_t<typename std::tuple_element<0, matrix_key_t<Matrix>>::type>;
+

Obtain the integer-like type used to store matrix indices.

+

Algorithms

+

Execution Policy

+

Execution policies are objects that indicate the kind of parallelism +allowed when executing an algorithm. For versions of GraphBLAS +algorithms that support execution policies, users may pass in the +execution policies defined in the C++ standard library.

+ +

GraphBLAS implementations may also provide implementation-defined +execution policies. Implementations must define the execution behavior +for any execution policies they define.

+

Exceptions and Error +Handling

+

Exceptions may be thrown to indicate error conditions. A number of +exceptions are defined which will be thrown in different error +conditions.

+

GraphBLAS-Defined Exceptions

+ +

Other Exceptions

+ +

std::bad_alloc. - Some functions and methods may +allocate memory using a user-provided allocator, which may throw.

+ +

Multiply

+

The function grb::multiply in GraphBLAS is used to +multiply a matrix times a matrix, a matrix times a vector, or a vector +times a matrix, depending on the types of the input arguments.

+

Matrix Times Matrix

+
template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+multiply_result_t<A, B, Reduce, Combine>
+multiply(A&& a,                                                                         (1)
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine = grb::multiplies<>,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+>
+void multiply(C&& c,                                                                    (2)
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+multiply_result_t<A, B, Reduce, Combine>
+multiply(ExecutionPolicy&& policy,                                                      (3)
+         A&& a,
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C
+>
+void multiply(ExecutionPolicy&& policy,                                                 (4)
+              C&& c,
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+

Matrix Times Vector

+
template <MatrixRange A,
+          VectorRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(A&& a,                                                                         (5)
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+
+template <MatrixRange A,
+          VectorRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine = grb::multiplies<>,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C,
+          BinaryOperator<grb::vector_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right<>
+>
+void multiply(C&& c,                                                                    (6)
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          VectorRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(A&& a,                                                                         (7)
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          VectorRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void multiply(C&& c,                                                                    (8)
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+

Vector Times Vector

+
template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(A&& a,                                                                         (9)
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{});
+
+template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          BinaryOperator<grb::vector_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          std::assignable_from<grb::combine_result_t<A, B, Combine>> C
+>
+void multiply(C&& c,                                                                   (10)
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(ExecutionPolicy&& policy,                                                     (11)
+         A&& a,
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{});
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          BinaryOperator<grb::vector_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          std::assignable_from<grb::combine_result_t<A, B, Combine>> C
+>
+void multiply(ExecutionPolicy&& policy,                                                (12)
+              C&& c,
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+

Vector Times Matrix

+
template <VectorRange A,
+          MatrixRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(A&& a,                                                                        (13)
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+template <VectorRange A,
+          MatrixRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine = grb::multiplies<>,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C,
+          BinaryOperator<grb::vector_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+>
+void multiply(C&& c,                                                                   (14)
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          MatrixRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+mutiply_result<A, B, Reduce, Combine>
+multiply(ExecutionPolicy&& policy,                                                     (15)
+         A&& a,
+         B&& b,
+         Reduce&& reduce = Reduce{},
+         Combine&& combine = Combine{},
+         M&& mask = M{});
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          MatrixRange B,
+          BinaryOperator<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
+          BinaryOperator<grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>,
+                         grb::combine_result_t<A, B, Combine>> Reduce,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::vector_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void multiply(ExecutionPolicy&& policy,                                                (16)
+              C&& c,
+              A&& a,
+              B&& b,
+              Reduce&& reduce = Reduce{},
+              Combine&& combine = Combine{},
+              M&& mask = M{},
+              Accumulate&& acc = Accumulate{},
+              bool merge = false);
+

Behavior is non-deterministic if reduce is not +associative or not commutative.

+

Parameters

+

policy - the execution policy to use

+

a - the left-hand side of the product being computed

+

b - the right-hand side of the product being +computed

+

reduce - a binary operator

+

combine - a binary operator

+

mask - write mask used to determine which elements of +the output will be computed

+

c - if given, the output object to which to write the +result

+

acc - the accumulator used to accumulate partial results +into the output object

+

merge - whether to merge in values from c +outside of the write area indicated by mask

+

Type Requirements

+ +

Return Value

+

If the output matrix or vector argument, c, is supplied, +no value is returned.

+

NOTE: `combine_result_t<A, B, Combine> is actually +incorrect here. Should be result of reduction.

+

If c is not supplied as an argument, returns the result +of the multiplication.

+
    +
    • +
    • A GraphBLAS matrix with shape a.shape()[0] by +b.shape()[1]
    • +
  1. +
    • +
    • A GraphBLAS vector with shape a.shape()[0]
    • +
  2. +
    • +
    • combine_result_t<A, B, Combine>
    • +
  3. +
    • +
    • A GraphBLAS vector with shape b.shape()[1]
    • +
  4. +
+

In the case that a GraphBLAS matrix or vector is returned, its scalar +type is combine_result_t<A, B, Combine>, and its +index type is equal to either grb::matrix_index_t<A> +or grb::matrix_index_t<B>, whichever one has the +larger std::numeric_limits<T>::max(). An element of +the result at index location index will only be computed if +a scalar value equal to true when converted to +bool exists in mask, that is +grb::find(mask, index) != grb::end(mask) && bool(grb::get<1>(*grb::find(mask, index))).

+
Matrix Times Matrix
+

A generalized matrix times matrix multiplication is performed, as +defined in the GraphBLAS Math +Specification. Each element of the output is produced by combing the +elements in corresponding indices of a row of a and column +of b and using reduce to perform a reduction +to a single value.

+
Matrix Times Vector
+

A generalized matrix times vector multiplication is performed, as +defined in the GraphBLAS Math +Specification. Each element of the output vector is produced by +combining elements in each row of a with the corresponding +elements of the vector b and using reduce to +perform a reduction of these to a single value in the output vector.

+
Vector Times Vector
+

A generalized dot product is performed, as defined in the GraphBLAS Math +Specification. The corresponding elements of vectors a +and b are combined and reduced into a single value using +reduce.

+
Vector Times Matrix
+

A generalized matrix times vector multiplication is performed, as +defined in the GraphBLAS Math +Specification. Each element of the output vector is produced by +combining elements in each column of b with the +corresponding elements of the vector a and using +reduce to perform a reduction of these to a single value in +the output vector.

+

Complexity

+

Complexity is implementation-defined.

+

Exceptions

+

The exception grb::invalid_argument may be thrown if any +of the following conditions occur:

+
Matrix Times Matrix
+ +
Matrix Times Vector
+ +
Vector Times Vector
+ +
Vector Times Matrix
+ +

If the algorithm fails to allocate memory, +std::bad_alloc is thrown.

+

Notes

+

Example

+

ewise_union

+

Perform an element-wise union between two GraphBLAS matrices or +vectors.

+

Element-Wise Matrix Union

+
template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+ewise_union_result_t<A, B, Combine>
+ewise_union(A&& a, B&& b, Combine&& combine, M&& mask = M{});                (1)
+
+template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_union(C&& c, A&& a, B&& b,
+                 Combine&& combine, M&& mask = M{},
+                 Accumulate&& acc = Accumulate{},
+                 bool merge = false);                                        (2)
+
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+ewise_union_result_t<A, B, Combine>
+ewise_union(ExecutionPolicy&& policy,
+            A&& a, B&& b,
+            Combine&& combine, M&& mask = M{});                              (3)
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_union(ExecutionPolicy&& policy,
+                 C&& c, A&& a, B&& b,
+                 Combine&& combine, M&& mask = M{},
+                 Accumulate&& acc = Accumulate{},
+                 bool merge = false);                                        (4)
+

Element-Wise Vector Union

+
template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>,
+                         grb::vector_scalar_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+ewise_union_result_t<A, B, Combine>
+ewise_union(A&& a, B&& b, Combine&& combine, M&& mask = M{});                (5)
+
+template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_union(C&& c, A&& a, B&& b,
+                 Combine&& combine, M&& mask = M{},
+                 Accumulate&& acc = Accumulate{},
+                 bool merge = false);                                        (6)
+
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t<A>,
+                         grb::vector_scalar_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>
+>
+ewise_union_result_t<A, B, Combine>
+ewise_union(ExecutionPolicy&& policy,
+            A&& a, B&& b,
+            Combine&& combine, M&& mask = M{});                              (7)
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_union(ExecutionPolicy&& policy,
+                 C&& c, A&& a, B&& b,
+                 Combine&& combine, M&& mask = M{},
+                 Accumulate&& acc = Accumulate{},
+                 bool merge = false);                                        (8)
+

Parameters

+

policy - the execution policy to use

+

a - matrix or vector on the left-hand side of the +element-wise operation

+

b - matrix or vector on the right-hand side of the +element-wise operation

+

c - output matrix or vector in which to store the result +of the multiply operation

+

combine - binary operator used to combine elements of +a and b

+

mask - determines which parts of the output matrix will +be computed

+

acc - binary operator used to combine elements of the +result with stored elements in corresponding locations in +c

+

merge - flag declaring whether to merge in elements of +c outside the range indicated by mask

+

Type Requirements

+ +

Return Value

+

If the output matrix or vector parameter, c, is +supplied, no value is returned.

+

If the parameter c is not supplied, the function returns +a GraphBLAS matrix (1,3) or GraphBLAS vector (5,7) equal to the +element-wise union of a and b, with the binary +operator combine used to combine scalar values stored at +the same index and mask used to determine which parts of +the output are computed. For (1,3), the type of the return value +satisfies the requirements of MatrixRange, and for (5,7) +the type of the return value satisfies the requirements of +VectorRange. The return value has the same shape as +a and b. Index idx in the return +value holds a stored value if and only if an element exists at that +index in both a or b and an element equal to +true when cast to bool exists at that index in +mask. If a value exists at idx in +a but not in b, the return value will hold a +value equal to a[idx]. If a value exists in b +but not in a, it will hold a value equal to +b[idx]. If a value exists at idx in both +a and b, it will hold a value equal to +fn(a[idx], b[idx]).

+

Preconditions

+

The parameters a and b must share the same +shape. If an output object c is given, it must also have +the same shape. For the parameter mask, each dimension of +its shape must be equal to or greater than the corresponding dimension +of a and b’s shapes. fn must not +modify any element of a, b, or +mask.

+

Postconditions

+

In (2,4) and (6,8), an element-wise union is performed as described +in the GraphBLAS Math +Specification and the result written to c. In (1,3) and +(5,7), none of the input arguments will be modified, and the result is +returned as a value.

+

Exceptions

+

The exception grb::invalid_argument may be thrown if any +of the following conditions occur:

+ +

Notes

+

Example

+
#include <grb/grb.hpp>
+
+int main(int argc, char** argv) {
+  grb::matrix<float> x({10, 10});
+  grb::matrix<float> y({10, 10});
+
+  x[{0, 1}] = 12;
+  x[{2, 5}] = 12;
+  x[{2, 7}] = 12;
+  x[{5, 3}] = 12;
+
+  y[{0, 1}] = 12;
+  y[{1, 5}] = 12;
+  y[{2, 7}] = 12;
+  y[{5, 3}] = 12;
+
+  auto z = grb::ewise_union(x, y, grb::plus{});
+
+  grb::print(z);
+
+  return 0;
+}
+

ewise_intersection

+

Perform an element-wise intersection between two GraphBLAS matrices +or vectors.

+

Element-Wise Matrix +Intersection

+
template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+ewise_intersection_result_t<A, B, Combine>
+ewise_intersection(A&& a, B&& b, Combine&& combine, M&& mask = M{});         (1)
+
+template <MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_intersection(C&& c, A&& a, B&& b,
+                        Combine&& combine, M&& mask = M{},
+                        Accumulate&& acc = Accumulate{},
+                        bool merge = false);                                 (2)
+
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>
+>
+ewise_intersection_result_t<A, B, Combine>
+ewise_intersection(ExecutionPolicy&& policy,
+                   A&& a, B&& b,
+                   Combine&& combine, M&& mask = M{});                       (3)
+
+template <typename ExecutionPolicy,
+          MatrixRange A,
+          MatrixRange B,
+          BinaryOperator<grb::matrix_scalar_t<A>,
+                         grb::matrix_scalar_t<B>> Combine,
+          MaskMatrixRange M = grb::full_matrix_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableMatrixRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_intersection(ExecutionPolicy&& policy,
+                        C&& c, A&& a, B&& b,
+                        Combine&& combine, M&& mask = M{},
+                        Accumulate&& acc = Accumulate{},
+                        bool merge = false);                                 (4)
+

Element-Wise Vector +Intersection

+
template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>
+          >
+ewise_intersection_result_t<A, B, Combine, M>
+ewise_intersection(A&& a, B&& b, Combine&& combine, M&& mask = M{});         (5)
+
+template <VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_intersection(C&& c, A&& a, B&& b,
+                        Combine&& combine, M&& mask = M{},
+                        Accumulate&& acc = Accumulate{},
+                        bool merge = false);                                 (6)
+
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>
+          >
+ewise_intersection_result_t<A, B, Combine, M>
+ewise_intersection(ExecutionPolicy&& policy,
+                   A&& a, B&& b,
+                   Combine&& combine, M&& mask = M{});                       (7)
+
+template <typename ExecutionPolicy,
+          VectorRange A,
+          VectorRange B,
+          BinaryOperator<grb::vector_scalar_t_t<A>,
+                         grb::vector_scalar_t_t<B>> Combine,
+          MaskVectorRange M = grb::full_vector_mask<>,
+          BinaryOperator<grb::matrix_scalar_t<C>,
+                         grb::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
+          MutableVectorRange<grb::combine_result_t<A, B, Combine>> C
+>
+void ewise_intersection(ExecutionPolicy&& policy,
+                        C&& c, A&& a, B&& b,
+                        Combine&& combine, M&& mask = M{},
+                        Accumulate&& acc = Accumulate{},
+                        bool merge = false);                                 (8)
+

Perform an element-wise intersection.

+

Parameters

+

policy - the execution policy to use

+

a - matrix or vector on the left-hand side of the +element-wise operation

+

b - matrix or vector on the right-hand side of the +element-wise operation

+

c - output matrix or vector in which to store the result +of the multiply operation

+

combine - binary operator used to combine elements of +a and b

+

mask - determines which parts of the output matrix will +be computed

+

acc - binary operator used to combine elements of the +result with stored elements in corresponding locations in +c

+

merge - flag declaring whether to merge in elements of +c outside the range indicated by mask

+

Type Requirements

+ +

Return Value

+

If the output matrix or vector parameter, c, is +supplied, no value is returned.

+

If the parameter c is not supplied, the function returns +a GraphBLAS matrix (1) or GraphBLAS vector (3) equal to the element-wise +intersection of a and b, with the binary +operator combine used to combine scalar values and +mask used to determine which parts of the output are +computed. For (1), the type of the return value satisfies the +requirements of MatrixRange, and for (3) the type of the +return value satisfies the requirements of VectorRange. The +return value has the same shape as a and b. +Index idx will only hold an element in the return value if +an element exists at idx in both a, +b, and mask, and the element of +mask holds a value equal to true when +converted to bool. The value at that index will be equal to +the value fn(a[idx], b[idx]).

+

Preconditions

+

The parameters a and b must share the same +shape. If an output object c is given, it must also have +the same shape. For the parameter mask, each dimension of +its shape must be equal to or greater than the corresponding dimension +of a and b’s shapes. fn must not +modify any element of a, b, or +mask.

+

Postconditions

+

In (2,4) and (6,8), an element-wise intersection is performed as +described in the GraphBLAS Math +Specification and the result written to c. In (1,3) and +(5,7), none of the input arguments will be modified, and the result is +returned as a value.

+

Exceptions

+

The exception grb::invalid_argument may be thrown if any +of the following conditions occur:

+ +

Notes

+

Example

+
#include <grb/grb.hpp>
+
+int main(int argc, char** argv) {
+  grb::matrix<float> x({10, 10});
+  grb::matrix<float> y({10, 10});
+
+  x[{0, 1}] = 12;
+  x[{2, 5}] = 12;
+  x[{2, 7}] = 12;
+  x[{5, 3}] = 12;
+
+  y[{0, 1}] = 12;
+  y[{1, 5}] = 12;
+  y[{2, 7}] = 12;
+  y[{5, 3}] = 12;
+
+  auto z = grb::ewise_intersection(x, y, grb::multiplies{});
+
+  grb::print(z);
+
+  return 0;
+}
+

assign

+
template <grb::MatrixRange B,
+          grb::MutableMatrixRange<grb::matrix_scalar_t<B>> A>
+void assign(A&& a, B&& b);                                                   (1)
+
+template <typename T, grb::MutableMatrixRange A<T>>
+void assign(A&& a, const T& value);                                          (2)
+
+
+template <grb::VectorRange V,
+          grb::MutableVectorRange<grb::vector_scalar_t<V> U>
+void assign(U&& u, V&& v);                                                   (3)
+
+
+template <typename T, grb::MutableVectorRange V<T>>
+void assign(U&& u, const T& value);                                          (4)
+

Assigns every element of a GraphbLAS matrix or vector to either (1, +3) another GraphBLAS matrix or vector with the same shape, or (2, 4) a +single scalar value.

+

Parameters

+

a - the matrix to be assigned

+

b - the matrix whose contents will be assigned to +a

+

u - the vector to be assigned

+

v - the vector whose contents will be assigned to +v

+

value - a scalar value to be assigned to every index +location in a

+

Type Requirements

+ +

Exceptions

+

The exception grb::invalid_argument is thrown if +a and b or u and v +are not the same shape. std::bad_alloc may be thrown if +a or u’s allocator is unable to allocate +memory.

+

Other exceptions may be thrown while assigning or constructing to +a or u.

+ + diff --git a/markdown/Makefile b/markdown/Makefile deleted file mode 100644 index 39f09c7..0000000 --- a/markdown/Makefile +++ /dev/null @@ -1,84 +0,0 @@ -TEX_SOURCES += $(wildcard *.tex) -MD_SOURCES += $(wildcard *.md) - -all: graphblas.pdf graphblas.html - -graphblas.html: $(TEX_SOURCES) $(MD_SOURCES) Makefile - pandoc -s \ - --toc \ - -o graphblas.html \ - metadata.md \ - intro.md \ - basic_concepts.md \ - --toc \ - --toc-depth=2 \ - -Vsecnumdepth=2 \ - --metadata title="GraphBLAS C++ API Specification v1.0" \ - matrix.md \ - vector.md \ - index.md \ - hints.md \ - views.md \ - functional.md \ - plus.md \ - multiplies.md \ - minus.md \ - divides.md \ - max.md \ - min.md \ - utilities.md \ - read_matrix.md \ - concepts.md \ - type_traits.md \ - matrix_traits.md \ - algorithms.md \ - execution_policy.md \ - exceptions.md \ - multiply.md \ - ewise_union.md \ - ewise_intersection.md \ - assign.md - # ops_mxm.md - -graphblas.pdf: $(TEX_SOURCES) $(MD_SOURCES) Makefile - pandoc -s \ - --top-level-division=chapter \ - -H preamble.tex \ - -B title.tex \ - -V geometry:margin=1in \ - -o graphblas.pdf \ - metadata.md \ - intro.md \ - basic_concepts.md \ - --toc \ - --toc-depth=2 \ - -Vsecnumdepth=2 \ - matrix.md \ - vector.md \ - index.md \ - hints.md \ - views.md \ - functional.md \ - plus.md \ - multiplies.md \ - minus.md \ - divides.md \ - max.md \ - min.md \ - utilities.md \ - read_matrix.md \ - concepts.md \ - type_traits.md \ - matrix_traits.md \ - algorithms.md \ - execution_policy.md \ - exceptions.md \ - multiply.md \ - ewise_union.md \ - ewise_intersection.md \ - assign.md - # ops_mxm.md - -clean: - rm -fv *.pdf *.html - diff --git a/markdown/algorithms.md b/markdown/algorithms.md deleted file mode 100644 index bc03301..0000000 --- a/markdown/algorithms.md +++ /dev/null @@ -1 +0,0 @@ -# Algorithms \ No newline at end of file diff --git a/markdown/assign.md b/markdown/assign.md deleted file mode 100644 index 22b6d25..0000000 --- a/markdown/assign.md +++ /dev/null @@ -1,49 +0,0 @@ -## `assign` - -```cpp -template > A> -void assign(A&& a, B&& b); (1) - -template > -void assign(A&& a, const T& value); (2) - - -template U> -void assign(U&& u, V&& v); (3) - - -template > -void assign(U&& u, const T& value); (4) -``` - -Assigns every element of a GraphbLAS matrix or vector to either (1, 3) another GraphBLAS matrix or vector with the same shape, or (2, 4) a single scalar value. - -### Parameters - -`a` - the matrix to be assigned - -`b` - the matrix whose contents will be assigned to `a` - -`u` - the vector to be assigned - -`v` - the vector whose contents will be assigned to `v` - -`value` - a scalar value to be assigned to every index location in `a` - -#### Type Requirements - -- `A` must be a mutable matrix range for the scalar value being assigned, that is it must meet the requirements of `grb::MutableMatrixRange>` (1) or `grb::MutableMatrixRange` (2) - -- `B` must meet the requirements of `grb::MatrixRange` - -- `U` must be a mutable vector range for the scalar value being assigned, that is it must meet the requirements of `grb::MutableVectorRange` (3) or `grb::MutableVectorRange` (4) - -- `V` must meet the requirements of `grb::VectorRange` - -### Exceptions -The exception `grb::invalid_argument` is thrown if `a` and `b` or `u` and `v` are not the same shape. -`std::bad_alloc` may be thrown if `a` or `u`'s allocator is unable to allocate memory. - -Other exceptions may be thrown while assigning or constructing to `a` or `u`. diff --git a/markdown/basic_concepts.md b/markdown/basic_concepts.md deleted file mode 100644 index f3740af..0000000 --- a/markdown/basic_concepts.md +++ /dev/null @@ -1,58 +0,0 @@ -# Basic Concepts - -GraphBLAS defines a collection of objects, functions, and concepts to facilitate -the implementation of graph algorithms. These programming facilities are further -separated into _GraphBLAS containers_, which include matrices and vectors, -_GraphBLAS operations_, which are algorithms such as matrix-vector multiplication that -operate over GraphBLAS containers, and _GraphBLAS operators_, which are binary and unary operators -that operate over scalar elements that may be held in a container. -The C++ API also defines a series of _concepts_ defining the interface a container -or operator must fulfill in order to to be used with a particular operation, as well -as _views_, which provide lazily evaluated, mutated views of a GraphBLAS object. - -## GraphBLAS Containers -GraphBLAS containers, which include matrices and vectors, are sparse data -structures holding a collection of stored scalar values. Each GraphBLAS container -has a shape, which defines the dimension(s) of the object. Stored values can be -inserted at indices within the dimensions of the object. Since GraphBLAS containers are -sparse, they keep explicit track of which index locations in the object hold -stored values. There is no implied zero value associated with a GraphBLAS -container, since the annhilator value will change from operation to operation, -and the insertion of explicit "zeros" could cause incorrect results. As such, -no GraphBLAS operation will arbitrarily insert explicit zeros. In the GraphBLAS -C++ API, each container has associated with it a scalar type, which is the type -of the stored scalar values, as well as an index type, which is the type used to -indicate the locations of stored values, as well as the matrix shape. - -___TODO: be more specific here. Could use some help from math spec?___ - -### Matrices -GraphBLAS matrices are two-dimensional sparse arrays. As previously discussed, -they have a scalar type, which defines the type of scalar values stored inside -the matrix, as well as an index type, which is used to refer to the row and column -index of each stored value. For a matrix type `A`, these types can be retrieved -using the expression `grb::matrix_scalar_t` to retrieve the scalar type and - `grb::matrix_index_t` to retrieve the index type. -In the GraphBLAS C++ API, matrices are associative arrays similar to -instantiations of `std::unordered_map`. They map keys, which are row and column -indices, to values, which are the stored scalar values. Like the C++ standard -library's associative containers, GraphBLAS matrices are ranges, and iterating -through a GraphBLAS matrix reveals a collection of tuples, with each tuple -holding a key and value. The key is a tuple-like type holding the row and column -indices, and the value is the stored scalar value. The row and column are provided -only as const references, while the value may be mutated. -Matrices also support insert, assign, and find operations to write or read to a -particular location in the matrix. - -### Vectors -GraphBLAS similars are analogous to matrices, except that they are only one-dimensional -sparse arrays. They hold a scalar type, which defines the scalar values stored -inside the vector, as well as an index type, which holds the index of an element -within the vector. For a vector `V`, these types can be retrieved with the -expressions `grb::vector_scalar_t` and `grb::vector_index_t`. -Like matrices, vectors are associative arrays, except that their key values are -a single index type element, and not a tuple. Like matrices, vectors are ranges, -with the value type being a tuple holding the index type and scalar type, with -only the scalar type being mutable if the vector is non-const. Individual elements -can be modified using insert, assign, and find. - diff --git a/markdown/concepts.md b/markdown/concepts.md deleted file mode 100644 index 8f83840..0000000 --- a/markdown/concepts.md +++ /dev/null @@ -1,299 +0,0 @@ -# Concepts - -## Binary Operator -Binary operators are function objects that are invocable with two arguments, returning a single value. -Binary operators can be callables defined by a GraphBLAS library, the C++ Standard Library, or application developers. -Binary operators may be callable with a variety of different types, or only with elements of a single type. -We say a binary operator is valid for a particular operation `T x U -> V` if it is callable with arguments of type `T` and `U` -and returns a value convertible to type `V`. - -### Requirements -1) Callable of type `Fn` can be invoked with two arguments of type `T` and `U`. -2) The return value is convertible to type `V`. - -#### Concept -```cpp -template -concept BinaryOperator = requires(Fn fn, T t, U u) { - {fn(t, u)} -> std::convertible_to; - }; -``` - -### Remarks -The last two arguments are defaulted unless explicit template parameters are provided. The second -parameter to the concept, `U`, which is the right-hand side input to the binary operator, defaults to -`T`. The final parameter, `V`, which represents the output of the binary operator, defaults to -`grb::any`, meaning that the return value may have any type. - -### Example - -```cpp -// Constrain `Fn` to require a binary operator that accepts two integers -// as arguments and returns a value of any type. -template Fn> -auto apply(Fn&& fn, int a, int b) { - return fn(a, b); -} - -// The following code will result in an error, since the function passed -// does not fulfill the BinaryOperator requirement, as it cannot accept -// integers. -void test() { - auto fn = [](std::string a, std::string b) { return a.size() + b.size(); }; - apply(fn, 12, 13); -} -``` - -## Monoid -*GraphBLAS monoids* are commutative monoids. Throughout this specification, they are referred to simply as monoids. They are binary operators that have -special properties when applied to elements of some type `T`. We say that a function object `Fn` forms on a monoid on type `T` if the -following requirements are met. - -### Requirements -1) Callable of type `Fn` fulfills the concept `BinaryOperator` for some type `T`. -2) The operation is associative and commutative for type `T`. -3) The operation has an identity element for type `T`, accessible using `grb::monoid_traits::identity()`. - - -#### Concept -```cpp -template -concept Monoid = BinaryOperator && - requires { {grb::monoid_traits::identity()} -> std::same_as; }; -``` - -## Tuple-Like Type -Tuple-like types are types that, similar to instantiations of `std::tuple` or `std::pair`, store multiple values. The number of values stored in the tuple-like type, as well as the type of each value, are known at compile time. We say that a type `T` is tuple-like for the parameter pack of types `Types` if it fulfills the following requirements. - -### Requirements -1) The tuple `T` has a size accessible using template `std::tuple_size` whose type is equal to `std::size_t` and whose value is equal to `sizeof...(Types)`. -2) The type of each stored value in the tuple `T` is accessible using `std::tuple_element`, with the N'th stored value equal to the N'th type in `Types`. -3) Each stored value in `T` is accessible using the customization point object `grb::get`, which will invoke either the method `get()` if it is present in the tuple type `T` or `std::get()`. The type of the return value for the N'th element must be convertible to the N'th element of `Types`. - -#### Concept -_TODO: this concept could refactored to be a bit more elegant. -```cpp -template -concept TupleElementGettable = requires(T tuple) { - {grb::get(tuple)} -> std::convertible_to; - }; -template -concept TupleLike = - requires { - typename std::tuple_size>::type; - requires std::same_as>)>, std::size_t>; - } && - sizeof...(Args) == std::tuple_size_v> && - [](std::index_sequence) { - return (TupleElementGettable && ...); - }(std::make_index_sequence>>()); -``` - -### Example - -```cpp -// The Concept `TupleLike` constraints `T` -// to be a tuple-like type storing int, int, float. -template T> -void print_tuple(T&& tuple) { - auto&& [i, j, v] = tuple; - printf("%d, %d, %f\n", i, j, v); -} -``` - -## Matrix Entry -Matrix entries represent entries in a GraphBLAS matrix, which include both a tuple-like index storing the row and column index of the stored scalar value, as well as the scalar value itself. We say that a type `Entry` is a valid matrix entry for the scalar type `T` and index type `I` if the following requirements are met. - -### Requirements -1) `Entry` is a tuple-like type with a size of 2. -2) The first element stored in the tuple-like type `Entry` is a tuple-like type fulfilling `TupleLike`, storing the row and column index of the matrix entry. -3) The second element stored in the tuple-like type `Entry` holds the matrix entry's scalar value, and is convertible to `T`. - -#### Concept - -```cpp -template -concept MatrixEntry = TupleLike && - requires(Entry entry) { {grb::get<0>(entry)} -> TupleLike; } && - requires(Entry entry) { {grb::get<1>(entry)} -> std::convertible_to; }; -``` - -## Mutable Matrix Entry -A mutable matrix entry is an entry in a matrix that fulfills all the requirements of matrix entry, but whose -stored scalar value can be mutated by assigning to some value of type `U`. We say that a matrix entry `Entry` is a mutable matrix entry for scalar type `T`, index type `I`, and output type `U`, if it fulfills all the requirements of matrix entry as well as the following requirements. - -### Requirements -1) The second element of the tuple `Entry`, representing the scalar value, is assignable to elements of type `U`. - -#### Concept - -```cpp -template -concept MutableMatrixEntry = MatrixEntry && - std::is_assignable_v(std::declval())), U>; -``` - -## Matrix Range -A matrix in GraphBLAS consists of a range of values distributed over a two-dimensional domain. In addition to [`grb::matrix`](#grb::matrix), which directly stores a collection of values, there are other types, such as views, that fulfill the same interface. We say that a type `M` is a matrix range if the following requirements are met. - -### Requirements -1) `M` has a scalar type of the stored values, accessible with `grb::matrix_scalar_t` -2) `M` has an index type used to reference the indices of the stored values, accessible with `grb::matrix_index_t`. -3) `M` is a range with a value type that represents a matrix tuple, containing both the index and scalar value for each stored value. -4) `M` has a shape, which is a tuple-like object of size two, holding the number of rows and the number of columns, accessible by invoking the method `shape()` on an object of type `M`. -5) `M` has a method `find()` that takes an index tuple and returns an iterator. - -#### Concept - -```cpp -template -concept MatrixRange = std::ranges::sized_range && - requires(M matrix) { - typename grb::matrix_scalar_t; - typename grb::matrix_index_t; - {std::declval>>()} - -> MatrixEntry, - grb::matrix_index_t>; - {grb::shape(matrix)} -> Tuplelike, - grb::matrix_index_t>; - {grb::find(matrix, {grb::matrix_index_t{}, grb::matrix_index_t{}})} - -> std::convertible_to>; - }; -``` -## Mutable Matrix Range -Some matrices and matrix-like objects are *mutable*, meaning that their stored values may be modified. Examples of mutable matrix ranges include instantiations of `grb::matrix` and certain matrix views that allow adding new values and modifying old values, such as `grb::transpose`. We say that a type `M` is a mutable matrix range for the scalar value `T` if the following requirements are met. - -### Requirements -1) `M` is a matrix range. -2) The value type of `M` fulfills the requirements of `MutableMatrixEntry`. -3) `M` has a method `insert()` that takes a matrix entry tuple and attempts to insert the element into the matrix, returning an iterator to the new element on success and returning an iterator to the end on failure. - -#### Concept - -```cpp -template -concept MutableMatrixRange = MatrixRange && - MutableMatrixEntry - grb::matrix_scalar_t, - grb::matrix_index_t, - T> && - requires(M matrix, T value) { - {grb::insert(matrix, {{grb::matrix_index_t{}, grb::matrix_index_t{}}, - value}) -> std::ranges::iterator_t; - } - }; -``` - -## Mask Matrix Range -Some operations require masks, which can be used to avoid computing and storing certain parts of the output. We say that a type `M` is a mask matrix range if the following requirements are met. - -### Requirements -1) `M` is a matrix range. -2) The scalar value type of `M` is convertible to `bool`. - -#### Concept - -```cpp -template -concept MaskMatrixRange = MatrixRange && - std::is_convertible_v, bool>; -``` - -## Vector Entry -Vector entries represent entries in a GraphBLAS vector, which include both an `std::integral` index storing the index of the stored scalar value, as well as the scalar value itself. We say that a type `Entry` is a valid matrix entry for the scalar type `T` and index type `I` if the following requirements are met. - -### Requirements -1) `Entry` is a tuple-like type with a size of 2. -2) The first element stored in the tuple-like type `Entry` fulfills `std::integral`. -3) The second element stored in the tuple-like type `Entry` holds the vector's scalar value, and is convertible to `T`. - -#### Concept - -```cpp -template -concept VectorEntry = TupleLike && - requires(Entry entry) { {grb::get<0>(entry)} -> std::integral; } && - requires(Entry entry) { {grb::get<1>(entry)} -> std::convertible_to; }; -``` - -## Mutable Vector Entry -A mutable vector entry is an entry in a vector that fulfills all the requirements of vector entry, but whose -stored scalar value can be mutated by assigning to some value of type `U`. We say that a vector entry `Entry` is a mutable vector entry for scalar type `T`, index type `I`, and output type `U`, if it fulfills all the requirements of vector entry as well as the following requirements. - -### Requirements -1) The second element of the tuple `Entry`, representing the scalar value, is assignable to elements of type `U`. - -#### Concept - -```cpp -template -concept MutableVectorEntry = VectorEntry && - std::is_assignable_v(std::declval())), U>; -``` - -## Vector Range -A vector in GraphBLAS consists of a range of values distributed over a one-dimensional domain. In addition to [`grb::vector`](#grb::vector), which directly stores a collection of values, there are other types, such as views, that fulfill the same interface. We say that a type `V` is a vector range if the following requirements are met. - -_TODO: make requirements list find CPO, not method._ - -### Requirements -1) `V` has a scalar type of the stored values, accessible with `grb::vector_scalar_t` -2) `V` has an index type used to reference the indices of the stored values, accessible with `grb::vector_index_t`. -3) `V` is a range with a value type that represents a vector tuple, containing both the index and scalar value for each stored value. -4) `V` has a shape, which is an integer-like object, holding the dimension of the vector, accessible by invoking the method `shape()` on an object of type `V`. -5) `V` has a method `find()` that takes an index and returns an iterator. - -#### Concept - -_TODO: this is a bit sketchy, and needs to have some of the components fleshed out._ -```cpp -template -concept VectorRange = std::ranges::sized_range && - requires(V vector) { - typename grb::vector_scalar_t; - typename grb::vector_index_t; - {std::declval>>()} - -> VectorEntry, - grb::vector_index_t>; - {grb::shape(vector)} -> std::same_as>; - {grb::find(vector, grb::vector_index_t)} -> std::convertible_to>; - }; -``` - -## Mutable Vector Range -Some vectors and vector-like objects are *mutable*, meaning that their stored values may be modified. Examples of mutable vector ranges include instantiations of `grb::vector` and certain vector views that allow adding new values and modifying old values, such as `grb::transpose`. We say that a type `V` is a mutable vector range for the scalar value `T` if the following requirements are met. - -### Requirements -1) `V` is a vector range. -2) The value type of `M` fulfills the requirements of `MutableVectorEntry`. -3) `M` has a method `insert()` that takes a vector entry tuple and attempts to insert the element into the vector returning an iterator to the new element on success and returning an iterator to the end on failure. - -#### Concept - -```cpp -template -concept MutableVectorRange = VectorRange && - MutableVectorEntry, - grb::vector_scalar_t, - grb::vector_index_t, - T> && - requires(V vector, T value) { - {grb::insert(vector, {grb::vector_index_t{}, value})} - -> std::same_as>; - }; -``` - -## Mask Vector Range -Some operations require masks, which can be used to avoid computing and storing certain parts of the output. We say that a type `M` is a mask vector range if the following requirements are met. - -### Requirements -1) `M` is a vector range. -2) The scalar value type of `M` is convertible to `bool`. - -#### Concept - -```cpp -template -concept MaskVectorRange = VectorRange && - std::is_convertible_v, bool>; -``` diff --git a/markdown/divides.md b/markdown/divides.md deleted file mode 100644 index edbb541..0000000 --- a/markdown/divides.md +++ /dev/null @@ -1,83 +0,0 @@ -## `grb::divides` - -```cpp -template -struct divides; -``` - -`grb::divides` is a binary operator that divides two values. - -### Specializations -Specialization | Description ------ | ----- -`divides` | deduces argument and return types -`divides` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the difference of the two arguments - -#### `grb::divides::operator()` - -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the difference of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to divide - -#### Return Value - -The result of `lhs / rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator/()` operation throws exceptions - -#### Monoid Traits - -`grb::divides` does not form a monoid for arithmetic types. - -### Specialization Details -#### `grb::divides` -```cpp -template <> -struct divides; -``` -Version of `grb::divides` with both arguments and return types deduced. - -#### `grb::divides::operator()` - -```cpp -template -constexpr auto operator()(T&& lhs, U&& rhs) const - -> decltype(std::forward(lhs) / std::forward(rhs)); -``` - -#### `grb::divides` - -```cpp -template -struct divides; -``` - -Version of `grb::divides` with explicit types for the arguments, but return type deduced. - -##### grb::divides::operator() - -```cpp -constexpr auto operator()(const T& lhs, const U& rhs) const - -> decltype(lhs / rhs); -``` diff --git a/markdown/ewise_intersection.md b/markdown/ewise_intersection.md deleted file mode 100644 index 956dcc8..0000000 --- a/markdown/ewise_intersection.md +++ /dev/null @@ -1,198 +0,0 @@ -## `ewise_intersection` - -Perform an element-wise intersection between two GraphBLAS matrices or vectors. - -#### Element-Wise Matrix Intersection -```cpp -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<> -> -ewise_intersection_result_t -ewise_intersection(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (1) - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableMatrixRange> C -> -void ewise_intersection(C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (2) - - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<> -> -ewise_intersection_result_t -ewise_intersection(ExecutionPolicy&& policy, - A&& a, B&& b, - Combine&& combine, M&& mask = M{}); (3) - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableMatrixRange> C -> -void ewise_intersection(ExecutionPolicy&& policy, - C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (4) -``` - -#### Element-Wise Vector Intersection -```cpp -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<> - > -ewise_intersection_result_t -ewise_intersection(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (5) - -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void ewise_intersection(C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (6) - - -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<> - > -ewise_intersection_result_t -ewise_intersection(ExecutionPolicy&& policy, - A&& a, B&& b, - Combine&& combine, M&& mask = M{}); (7) - -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void ewise_intersection(ExecutionPolicy&& policy, - C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (8) -``` - -Perform an element-wise intersection. - -### Parameters - -`policy` - the execution policy to use - -`a` - matrix or vector on the left-hand side of the element-wise operation - -`b` - matrix or vector on the right-hand side of the element-wise operation - -`c` - output matrix or vector in which to store the result of the multiply operation - -`combine` - binary operator used to combine elements of `a` and `b` - -`mask` - determines which parts of the output matrix will be computed - -`acc` - binary operator used to combine elements of the result with stored elements in corresponding locations in `c` - -`merge` - flag declaring whether to merge in elements of `c` outside the range indicated by `mask` - -#### Type Requirements - -- `A` must meet the requirements of `MatrixRange` (1,2,3,4) or `VectorRange` (5,6,7,8). - -- `B` must meet the requirements of `MatrixRange` (1,2,3,4) or `VectorRange` (5,6,7,8). - -- `C` must meet the requirements of `MutableMatrixRange>` (2,4) or `MutableVectorRange>` (6,8). - -- `Combine` must meet the requirements of `BinaryOperator, grb::matrix_scalar_t>` (1,2,3,4) or `BinaryOperator, grb::vector_scalar_t>` (5,6,7,8). - -- `M` must meet the requirements of `MaskMatrixRange` (1,2,3,4) or `MaskVectorRange` (5,6,7,8). - -- `Accumulate` must meet the requirements of `BinaryOperator, grb::combine_result_t>` (2,4) or `BinaryOperator, grb::combine_result_t>` (6,8). - -### Return Value - -If the output matrix or vector parameter, `c`, is supplied, no value is returned. - -If the parameter `c` is not supplied, the function returns a GraphBLAS matrix (1) or GraphBLAS vector (3) equal to the element-wise intersection of `a` and `b`, with the binary operator `combine` used to combine scalar values and `mask` used to determine which parts of the output are computed. For (1), the type of the return value satisfies the requirements of `MatrixRange`, and for (3) the type of the return value satisfies the requirements of `VectorRange`. The return value has the same shape as `a` and `b`. Index `idx` will only hold an element in the return value if an element exists at `idx` in both `a`, `b`, and `mask`, and the element of `mask` holds a value equal to `true` when converted to `bool`. The value at that index will be equal to the value `fn(a[idx], b[idx])`. - -### Preconditions - -The parameters `a` and `b` must share the same shape. If an output object `c` is given, it must also have the same shape. For the parameter `mask`, each dimension of its shape must be equal to or greater than the corresponding dimension of `a` and `b`'s shapes. `fn` must not modify any element of `a`, `b`, or `mask`. - -### Postconditions - -In (2,4) and (6,8), an element-wise intersection is performed as described in the [GraphBLAS Math Specification](https://github.com/GraphBLAS/graphblas-api-math) and the result written to `c`. In (1,3) and (5,7), none of the input arguments will be modified, and the result is returned as a value. - -### Exceptions - -The exception `grb::invalid_argument` may be thrown if any of the following conditions occur: - -- The dimensions of `a` and `b` incompatible, that is `a.shape() != b.shape()`. -- The dimensions of `c`, if given, does not match `a`'s shape, that is `c.shape() != a.shape()` -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape()[0] < a.shape()[0] || mask.shape()[1] < a.shape()[1]` (1,2,3,4) or `mask.shape() < a.shape()` (5,6,7,8). - -### Notes - -### Example - -```cpp -#include - -int main(int argc, char** argv) { - grb::matrix x({10, 10}); - grb::matrix y({10, 10}); - - x[{0, 1}] = 12; - x[{2, 5}] = 12; - x[{2, 7}] = 12; - x[{5, 3}] = 12; - - y[{0, 1}] = 12; - y[{1, 5}] = 12; - y[{2, 7}] = 12; - y[{5, 3}] = 12; - - auto z = grb::ewise_intersection(x, y, grb::multiplies{}); - - grb::print(z); - - return 0; -} -``` diff --git a/markdown/ewise_union.md b/markdown/ewise_union.md deleted file mode 100644 index ff83ae2..0000000 --- a/markdown/ewise_union.md +++ /dev/null @@ -1,198 +0,0 @@ -## `ewise_union` - -Perform an element-wise union between two GraphBLAS matrices or vectors. - -#### Element-Wise Matrix Union - -```cpp -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<> -> -ewise_union_result_t -ewise_union(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (1) - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableMatrixRange> C -> -void ewise_union(C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (2) - - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<> -> -ewise_union_result_t -ewise_union(ExecutionPolicy&& policy, - A&& a, B&& b, - Combine&& combine, M&& mask = M{}); (3) - -template , - grb::matrix_scalar_t> Combine, - MaskMatrixRange M = grb::full_matrix_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableMatrixRange> C -> -void ewise_union(ExecutionPolicy&& policy, - C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (4) -``` - -#### Element-Wise Vector Union - -```cpp -template , - grb::vector_scalar_t> Combine, - MaskVectorRange M = grb::full_vector_mask<> -> -ewise_union_result_t -ewise_union(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (5) - -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void ewise_union(C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (6) - - -template , - grb::vector_scalar_t> Combine, - MaskVectorRange M = grb::full_vector_mask<> -> -ewise_union_result_t -ewise_union(ExecutionPolicy&& policy, - A&& a, B&& b, - Combine&& combine, M&& mask = M{}); (7) - -template , - grb::vector_scalar_t_t> Combine, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void ewise_union(ExecutionPolicy&& policy, - C&& c, A&& a, B&& b, - Combine&& combine, M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); (8) -``` - -### Parameters - -`policy` - the execution policy to use - -`a` - matrix or vector on the left-hand side of the element-wise operation - -`b` - matrix or vector on the right-hand side of the element-wise operation - -`c` - output matrix or vector in which to store the result of the multiply operation - -`combine` - binary operator used to combine elements of `a` and `b` - -`mask` - determines which parts of the output matrix will be computed - -`acc` - binary operator used to combine elements of the result with stored elements in corresponding locations in `c` - -`merge` - flag declaring whether to merge in elements of `c` outside the range indicated by `mask` - -#### Type Requirements - -- `A` must meet the requirements of `MatrixRange` (1,2,3,4) or `VectorRange` (5,6,7,8). - -- `B` must meet the requirements of `MatrixRange` (1,2,3,4) or `VectorRange` (5,6,7,8). - -- `C` must meet the requirements of `MutableMatrixRange>` (2,4) or `MutableVectorRange>` (6,8). - -- `Combine` must meet the requirements of `BinaryOperator, grb::matrix_scalar_t>` (1,2,3,4) or `BinaryOperator, grb::vector_scalar_t>` (5,6,7,8). - -- `M` must meet the requirements of `MaskMatrixRange` (1,2,3,4) or `MaskVectorRange` (5,6,7,8). - -- `Accumulate` must meet the requirements of `BinaryOperator, grb::combine_result_t>` (2,4) or `BinaryOperator, grb::combine_result_t>` (6,8). - -### Return Value - -If the output matrix or vector parameter, `c`, is supplied, no value is returned. - -If the parameter `c` is not supplied, the function returns a GraphBLAS matrix (1,3) or GraphBLAS vector (5,7) equal to the element-wise union of `a` and `b`, with the binary operator `combine` used to combine scalar values stored at the same index and `mask` used to determine which parts of the output are computed. For (1,3), the type of the return value satisfies the requirements of `MatrixRange`, and for (5,7) the type of the return value satisfies the requirements of `VectorRange`. The return value has the same shape as `a` and `b`. Index `idx` in the return value holds a stored value if and only if an element exists at that index in both `a` or `b` and an element equal to `true` when cast to `bool` exists at that index in `mask`. If a value exists at `idx` in `a` but not in `b`, the return value will hold a value equal to `a[idx]`. If a value exists in `b` but not in `a`, it will hold a value equal to `b[idx]`. If a value exists at `idx` in both `a` and `b`, it will hold a value equal to `fn(a[idx], b[idx])`. - -### Preconditions - -The parameters `a` and `b` must share the same shape. If an output object `c` is given, it must also have the same shape. For the parameter `mask`, each dimension of its shape must be equal to or greater than the corresponding dimension of `a` and `b`'s shapes. `fn` must not modify any element of `a`, `b`, or `mask`. - -### Postconditions - -In (2,4) and (6,8), an element-wise union is performed as described in the [GraphBLAS Math Specification](https://github.com/GraphBLAS/graphblas-api-math) and the result written to `c`. In (1,3) and (5,7), none of the input arguments will be modified, and the result is returned as a value. - -### Exceptions - -The exception `grb::invalid_argument` may be thrown if any of the following conditions occur: - -- The dimensions of `a` and `b` incompatible, that is `a.shape() != b.shape()`. -- The dimensions of `c`, if given, does not match `a`'s shape, that is `c.shape() != a.shape()` -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape()[0] < a.shape()[0] || mask.shape()[1] < a.shape()[1]` (1,2,3,4) or `mask.shape() < a.shape()` in (5,6,7,8). - -### Notes - -### Example - -```cpp -#include - -int main(int argc, char** argv) { - grb::matrix x({10, 10}); - grb::matrix y({10, 10}); - - x[{0, 1}] = 12; - x[{2, 5}] = 12; - x[{2, 7}] = 12; - x[{5, 3}] = 12; - - y[{0, 1}] = 12; - y[{1, 5}] = 12; - y[{2, 7}] = 12; - y[{5, 3}] = 12; - - auto z = grb::ewise_union(x, y, grb::plus{}); - - grb::print(z); - - return 0; -} -``` diff --git a/markdown/exceptions.md b/markdown/exceptions.md deleted file mode 100644 index 262ae4f..0000000 --- a/markdown/exceptions.md +++ /dev/null @@ -1,20 +0,0 @@ -## Exceptions and Error Handling - -Exceptions may be thrown to indicate error conditions. A number of exceptions -are defined which will be thrown in different error conditions. - -### GraphBLAS-Defined Exceptions -- `grb::out_of_range` is thrown if an index is provided which lies outside the - dimensions of the matrix, or if a value is not present at the index. - -- `grb::matrix_io::file_error` is thrown if a file cannot be read. - -- `grb::invalid_argument` is thrown if objects' dimensions are incompatible. - -### Other Exceptions -- Some functions and methods may allocate temporary memory. These may throw - -`std::bad_alloc`. -- Some functions and methods may allocate memory using a user-provided allocator, which may throw. - -- Some functions and methods accept user-defined binary or unary operators. These may throw. diff --git a/markdown/execution_policy.md b/markdown/execution_policy.md deleted file mode 100644 index 31ef3ff..0000000 --- a/markdown/execution_policy.md +++ /dev/null @@ -1,15 +0,0 @@ -## Execution Policy - -Execution policies are objects that indicate the kind of parallelism allowed -when executing an algorithm. For versions of GraphBLAS algorithms that support -execution policies, users may pass in the execution policies defined in the C++ -standard library. - -- `std::execution::sequenced_policy` -- `std::execution::parallel_policy` -- `std::execution::parallel_unsequenced_policy` -- `std::execution::unsequenced_policy` - -GraphBLAS implementations may also provide implementation-defined execution -policies. Implementations must define the execution behavior for any -execution policies they define. \ No newline at end of file diff --git a/markdown/functional.md b/markdown/functional.md deleted file mode 100644 index 7cfe76f..0000000 --- a/markdown/functional.md +++ /dev/null @@ -1,121 +0,0 @@ -# Pre-Defined Operators -The GraphBLAS C++ API defines a number of binary and unary operators. Operators are defined as -function objects and typically perform arithmetic or logical operations like addition, multiplication, -negation, and logical and. - -#### TODO: Discuss Unary Operators -They work the same way as binary operators, but are quite a bit simpler, since there is only one value to operate upon. - -## Binary Operator Template Parameters -GraphBLAS's binary operators allow flexiblility in terms of whether all, some, or none of -the types are explicitly declared. If one or more types are not explicitly declared, -they are deduced at the callsite where the operator is invoked. For each binary operator -`op`, there are three partial specializations defined: - -1) `op`, where the input arguments are explicitly specified to be `T` and `U` and the return value is `V`. -2) `op`, where the input arguments are explicitly specified to be `T` and `U`, and the return value is deduced. -3) `op`, where the inputs arguments and return type are all deduced upon invocation. - -All binary operators have the following default template parameters: - -```cpp -template -struct op; -``` - -This means the user can use a binary operator with zero, one, two, or three template parameters explicitly specified. -The types of the input arguments and return value will be explicitly defined or reduced accordingly. - -#### No Types Specified -If a user specifies no template parameters when using a binary operator, the result is a function object in which the -input argument and return value types are all deduced at the callsite. - -```cpp -#include -#include -int main(int argc, char** argv) { - // No types are explicitly specified. - // We can use this operator with values of - // any types for which an operator+() is defined. - grb::plus<> p1; - - std::size_t a = 1024; - std::uint8_t b = 12; - - // `std::size_t` and `std::uint8_t` deduced as types of input arguments. - // `std::size_t` will be deduced as type of return value. - // std::size_t + std::uint8_t -> std::size_t - auto c = p1(a, b); - - return 0; -} -``` - -#### One Type Specified -If a user specifies one template parameters when using a binary operator, the result is a function object in which the -the two input arguments are of the type specified, and the return value type is deduced. - -```cpp -#include -#include -int main(int argc, char** argv) { - // Explicitly specify `int` as the type of both input values. - // Return value type will be deduced as `int`. - grb::plus p1; - - int a = 1024; - int b = 12; - - // int + int -> int - int c = p1(a, b); - - return 0; -} -``` - -#### Two Types Specified -If a user specifies two template parameters when using a binary operator, the result is a function object in which the -the two input arguments are of the types specified, and the return value type is deduced. - -```cpp -#include -#include -int main(int argc, char** argv) { - // Explicitly specify `std::size_t` for the lefthand argument - // and `std::uint8_t` for the righthand argument. - // Return value type will be deduced as `std::size_t`. - grb::plus p1; - - std::size_t a = 1024; - std::uint8_t b = 12; - - // std::size_t + std::uint8_t -> std::size_t - std::size_t c = p1(a, b); - - return 0; -} -``` - -#### Three Types Specified -If a user specifies all three template parameters when using a binary operator, both of the input argument types -as well as the return value type of the function are explicitly specified. - -```cpp -#include -#include -int main(int argc, char** argv) { - // Explicitly specify `std::size_t` for the lefthand argument - // and `std::uint8_t` for the righthand argument. - // Return value type explicitly specified as `int`. - grb::plus p1; - - std::size_t a = 1024; - std::uint8_t b = 12; - - // std::size_t + std::uint8_t -> std::size_t - std::size_t c = p1(a, b); - - return 0; -} -``` - diff --git a/markdown/hints.md b/markdown/hints.md deleted file mode 100644 index 6b348fd..0000000 --- a/markdown/hints.md +++ /dev/null @@ -1,75 +0,0 @@ -# Sparse Storage Format Hints - -This section defines compile-time hints that can be used to direct the storage format used to organize data inside GraphBLAS objects. Storage hints can be used as optional template arguments to `grb::matrix`, `grb::vector`, as well as some API functions that return a matrix or vector. These compile-time hints provide a mechanism for users to suggest to the GraphBLAS implementation which storage format might be most appropriate for a particular matrix. However, these compile-time hints are indeed *hints* to the implementation and do not enforce any change in semantics to a matrix or vector data structure and do not require it to use any particular storage format. GraphBLAS implementations are encouraged to document which storage formats they support, as well as how different hints will affect which storage formats are used. - -### Example - -```cpp -#include - -int main(int argc, char** argv) { - // Create a matrix with the `dense` compile-time hint. - // The implementation may choose to employ a dense storage format. - grb::matrix x({10, 10}); - - // Create a matrix with the compile-time hint compose. - // A GraphBLAS implementation may choose to employ a compressed sparse row - // storage format. - grb::matrix> y({10, 10}); - - - // No change in data structure semantics is implied by a hint. - x[{2, 3}] = 12; - x[{3, 6}] = 12; - - y[{6, 7}] = 1; - y[{6, 7}] = 2.5; - - grb::print(x); - grb::print(y); - - return 0; -} -``` - - -## `grb::sparse` - -```cpp -using sparse = /* undefined */; -``` - -Compile-time hint to suggest to the GraphBLAS implementation that a sparse or compressed storage format is appropriate. - -## `grb::dense` - -```cpp -using dense = /* undefined */; -``` - -Compile-time hint to suggest to the GraphBLAS implementation that a dense storage format is appropriate. - -## `grb::row` - -```cpp -using row = /* undefined */; -``` - -Compile-time hint to suggest to the GraphBLAS implementation that a row-major storage format is appropriate. - -## `grb::column` - -```cpp -using column = /* undefined */; -``` - -Compile-time hint to suggest to the GraphBLAS implementation that a column-major storage format is appropriate. - -## `grb::compose` - -```cpp -template -using compose = /* undefined */; -``` - -Type alias used to combine multiple compile-time hints together. diff --git a/markdown/index.md b/markdown/index.md deleted file mode 100644 index 00cfc82..0000000 --- a/markdown/index.md +++ /dev/null @@ -1,32 +0,0 @@ -# `grb::index` - -```cpp -template -struct grb::index; -``` - -`grb::index` is a tuple-like type used to store matrix indices and dimensions. - -## Template Parameters -`T` - type, satisfying `std::integral`, used to store indices - -## Member Types -Member Type | Definition ------ | ----- -`index_type` | `T` -`first_type` | `T` -`second_type` | `T` - -## Member Objects -Member Name | Type ------ | ----- -`first` | `T` -`second` | `T` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs index -`operator[]` | Get one of the indices -`get` | Get one of the indices - diff --git a/markdown/intro.md b/markdown/intro.md deleted file mode 100644 index efe17a7..0000000 --- a/markdown/intro.md +++ /dev/null @@ -1,66 +0,0 @@ -# Intro -The GraphBLAS standard defines a set of generalized matrix and vector operations based -on semiring algebraic structures. These operations can be used to express a wide variety -of graph algorithms. This specification document defines the C++ programming interface for the -GraphBLAS standard, referred to as the \emph{GraphBLAS C++ API (Application Programming Interface)}. -The GraphBLAS C++ API defines a collection of data structures, algorithms, views, -operators, and concepts for implementing graph algorithms. These API components -are based around mathematical objects, such as matrices and vectors, and -operations, such as generalized matrix multiplication and element-wise operations. -The [GraphBLAS Math Specification](https://github.com/GraphBLAS/graphblas-api-math) -provides a complete specification of the mechanics of these structures and operations, and provides a rigorous mathematical definition of the operations -and data structures provided in this specification. - -## Data Structures -This specification provides data structures for storing matrices and vectors. -These implement the matrix and vector range [concepts](#concepts) also defined -in this specification. - -### Matrices -Matrices are two-dimensional collections of sparse values. Each matrix has a -defined number of rows and columns, which define its \emph{shape}. In addition, -each matrix has a defined number of \emph{stored values}, which are indices -inside the bounds of the matrix which actually contain scalar values. A matrix -has a fixed \emph{scalar type}, which is the type of the stored values, as well -as an \emph{index type}, which is the type of the indices. - -GraphBLAS matrices are sparse, consist of a well-defined set of stored values, -and have no implicit zero value for empty indices. As such, operations may not -arbitrarily insert explicit zero values into the matrix, but must produce an -output with the exact set of values as specified by the GraphBLAS Math -Specification. - -The GraphBLAS matrix data structure defined in this specification, `grb::matrix`, -provides mechanisms for creating, manipulating, and iterating through -GraphBLAS matrices. It also includes a mechanism for influencing the storage -format through compile-time hints. GraphBLAS operations that accept matrices -can be called with other types so long as they fulfill the GraphBLAS matrix concepts. - -### Vectors -Vectors are one-dimensional collections of sparse values. Each vector has a -defined number of indices, which defines its shape. Similarly, it has a defined -number of stored stored values, which must lie at indices within its shape. Its -scalar values have a fixed scalar type, and it has a fixed index type for storing -indices. Vectors follow the same sparsity rules as matrices, and similarly -the GraphBLAS matrix concepts. - -## Concepts -The GraphBLAS C++ Specification defines matrix and vector concepts. These -define the interface that a type must support in order to be used by GraphBLAS -operations. The intention is that data structures defined by other libraries -may be used in GraphBLAS operations so long as they define a small number of -customization points that perform insert, find, and iteration operations over -the matrix or vector. - -### Version Conformance -A C++ GraphBLAS library should define the macro `GRAPHBLAS_CPP_VERSION` to indicate its -level of conformance with the GraphBLAS C++ API. To indicate conformance with the -GraphBLAS 0.1a draft specification, a library should provide the macro `GRAPHBLAS_CPP_VERSION` -with a value greater than or equal to `202207L`. - -#### Exposition Only -```cpp -// Define the `GRAPHBLAS_CPP_VERSION` macro to indicate -// conformance to the GraphBLAS 0.1 Draft Specification. -#define GRAPHBLAS_CPP_VERSION 202207L -``` \ No newline at end of file diff --git a/markdown/matrix.md b/markdown/matrix.md deleted file mode 100644 index a442a38..0000000 --- a/markdown/matrix.md +++ /dev/null @@ -1,374 +0,0 @@ -# `grb::matrix` - -```cpp -template > -class grb::matrix; -``` - -## Template Parameters -`T` - type of scalar values stored in the matrix - -`I` - type, satisfying `std::integral`, used to store indices in the matrix - -`Hint` - one or a composition of compile-time hints that may be used to affect the backend storage type - -`Allocator` - allocator type used to allocate memory for the matrix - -## Member Types -Member Type | Definition ------ | ----- -`scalar_type` | `T`, the type of elements stored in the matrix -`index_type` | `I`, an integer type used to store matrix indices -`key_type` | A tuple-like type storing two `index_type` elements -`map_type` | `scalar_type` -`value_type` | `grb::matrix_entry`, a tuple-like type storing the indices and the stored element -`size_type` | A large unsigned integer type, usually `std::size_t` -`difference_type` | A large signed integer type, usually `std::ptrdiff_t` -`allocator_type` | `Allocator` -`iterator` | An iterator type fulfilling `std::forward_iterator` -`const_iterator` | A const iterator fulfilling `std::forward_iterator` -`reference` | `grb::matrix_reference` -`const_reference` | `grb::matrix_reference` -`scalar_reference` | Reference to `scalar_type` -`const_scalar_reference` | Const reference to `scalar_type` -`hint_type` | `Hint` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs matrix -`(destructor)` | Destructs matrix -`operator=` | Assigns matrix -`size` | Number of stored elements in matrix -`max_size` | Returns the maximum possible number of elements -`empty` | Return whether the matrix is empty -`shape` | Return the dimensions of the matrix -`begin`
`cbegin` | Returns iterator to beginning of container -`end`
`cend` | Returns iterator to one past last element in container -`reshape` | Modify dimensions of the matrix -`clear` | Clears all elements from the container -`insert` | Insert elements -`insert_or_assign` | Inserts or assigns elements -`erase` | Erases elements -`find` | Finds an element -`at` | Access element -`operator[]` | Access or insert element - -## `grb::matrix::matrix` - -```cpp -matrix(const Allocator& alloc = Allocator()); (1) -matrix(grb::index shape, - const Allocator& alloc = Allocator()); (2) -matrix(const matrix& other); (3) -matrix(matrix&& other); (4) -``` - -Constructs new `grb::matrix` data structure. - -1) Constructs an empty matrix of dimension `0 x 0`. -2) Constructs an empty matrix of dimension `shape[0] x shape[1]`. -3) Copy constructor. Constructs a matrix with the dimensions and contents of `other`. -4) Move constructor. Constructs a matrix with the dimensions and contents of `other` using move semantics. After the move, `other` is guaranteed to be empty. - -### Parameters -`shape` - shape of the matrix to be constructed - -`other` - another matrix to construct the new matrix from - -### Complexity -1) Constant -2) Implementation defined -3) Implementation defined -4) Implementation defined - -### Exceptions -Calls to `Allocator::allocate` may throw. - -## `grb::matrix::~matrix` - -```cpp -~matrix(); -``` - -Destroys the `grb::matrix`. The destructors of the elements are called and -storage is deallocated. - -### Complexity -Linear in the size of the vector. - -## `grb::matrix::operator=` - -```cpp -matrix& operator=(const matrix& other); (1) -matrix& operator=(matrix&& other); (2) -``` - -Replaces the matrix with the contents and shape of another matrix. - -1) Copy assignment operator. Modifies the shape of the matrix to be equal to that of `other` and copies the stored values to be the same as `other`. -2) Move constructor. Replaces the contents of the matrix with those of `other` using move semantics. After the move assignment operation completes, `other` is in a valid but indeterminate state. - -### Parameters -`other` - another matrix to assign the matrix to - -### Complexity -1) Implementation defined -2) Constant - -### Exceptions -1) Calls to `Allocator::allocate` may throw. - -## `grb::matrix::size` -```cpp -size_type size() noexcept; -``` - -Returns the number of elements stored in the matrix. - -### Parameters -(none) - -### Return value -Number of stored elements. - -### Complexity -Constant - -## `grb::matrix::max_size` -```cpp -size_type max_size() const noexcept; -``` - -Returns the maximum possible number of elements that could be stored in the matrix due to system or implementation limitations. - -### Parameters -(none) - -### Return value -Maximum possible number of elements. - -### Complexity -Constant - -## `grb::matrix::empty` -```cpp -bool empty() noexcept; -``` - -Returns whether the matrix is empty, that is where `size() == 0`. - -### Parameters -(none) - -### Return value -Whether the matrix is empty. - -### Complexity -Constant - -## `grb::matrix::shape` -```cpp -grb::index shape() const noexcept; -``` - -Returns the dimensions of the matrix. - -### Parameters -(none) - -### Return value -Dimensions of the matrix. - -### Complexity -Constant - -## `grb::matrix::begin` and `grb::matrix::cbegin` -```cpp -iterator begin() noexcept; -const_iterator begin() const noexcept; -const_iterator cbegin() const noexcept; -``` - -Returns an iterator to the first element of the matrix data structure. If the matrix is empty, returns an element that compares as equal to `end()`. - -### Parameters -(none) - -### Return value -Iterator to the first element - -### Complexity -Constant - -## `grb::matrix::end` and `grb::matrix::cend` -```cpp -iterator end() noexcept; -const_iterator end() const noexcept; -const_iterator cend() const noexcept; -``` - -Returns an iterator to one past the last element of the matrix data structure. This element is used only to signify the end of the container, and accessing it has undefined behavior. - -### Parameters -(none) - -### Return value -Iterator to one past the last element. - -### Complexity -Constant - -## `grb::matrix::reshape` -```cpp -void reshape(grb::index shape) noexcept; -``` - -Reshape the matrix. That is, modify the matrix dimensions such that matrix shape is now `shape[0]` x `shape[1]`. -If any nonzeros lie outside of the new matrix shape, they are removed from the matrix - -### Parameters -`shape` - New matrix shape - -### Return value -None - -### Complexity -Implementation defined - -### Exceptions -Calls to `Allocator::allocate` may throw. - -## `grb::matrix::clear` -```cpp -void clear() noexcept; -``` - -Clear all stored scalar values from the matrix. The matrix maintains the same shape, but after return will now have a size of 0. - -### Complexity -Implementation defined - -## `grb::matrix::insert` -```cpp -template -void insert(InputIt first, InputIt last); (1) -std::pair insert(const value_type& value); (2) -std::pair insert(value_type&& value); (3) -``` - -Inserts an element or number of elements into the matrix, if the matrix doesn't already contain a stored element at the corresponding index. - -(1) Insert each element in the range `[first, last)` if an element does not already exist in the matrix at the corresponding index. If multiple elements in `[first, last)` have the same indices, it is undefined which element is inserted. - -(2) and (3) Insert the element `value` if an element does not already exist at the corresponding index in the matrix. - -### Parameters -`first`, `last` - Range of elements to insert - -`value` - element to insert - -### Return value -(1) None - -(2) and (3) return a `std::pair` containing an `iterator` and a `bool` value. The `bool` value indicates whether or not the insertion was successful. If the insertion was successful, the first value contains an iterator to the newly inserted element. If it was unsuccessful, it contains an iterator to the element that prevented insertion. - -### Complexity -Implementation defined - -## `grb::matrix::insert_or_assign` -```cpp -template -std::pair insert_or_assign(key_type k, M&& obj); -``` - -Inserts an element into index `k` in the matrix and assigns to the scalar value if one already exists. - -If an element already exists at index location `k`, assigns `std::forward(obj)` to the scalar value stored at that index. If no element exists, inserts `obj` at the index as if by calling `insert` with `value_type(k, std::forward(obj))`. - -### Parameters -`k` - the index location to assign `obj` - -`obj` - the scalar value to be assigned - -### Type Requirements -`M` must fulfill `std::is_assignable` - -### Return Value -Returns an `std::pair` with the first element holding an iterator to the newly inserted or assigned value and the second element holding a `bool` value that is `true` if the element was inserted and `false` otherwise. - -### Complexity -Implementation defined. - -## `grb::matrix::erase` -```cpp -size_type erase(grb::index index); -``` - -Erases the element stored at index `index` if one exists. - -### Parameters -`index` - the index of element to erase - -### Return Value -Returns the number of elements erased (0 or 1). - -### Complexity -Implementation defined. - -## `grb::matrix::find` -```cpp -iterator find(grb::index index); -const_iterator find(grb::index index) const; -``` - -Finds the element at location (`index[0]`, `index[1]`) in the matrix, returning an iterator to the element. If no element is present at the location, returns `end()`. - -### Parameters -`index` - Location of the matrix element to find - -### Return value -An iterator pointing to the matrix element at the corresponding index, or `end()` if there is no element at the location. - -### Complexity -Implementation defined - -## `grb::matrix::operator[]` -```cpp -scalar_reference operator[](grb::index index); -const_scalar_reference operator[](grb::index index) const; -``` - -Returns a reference to the scalar value stored at location (`index[0]`, `index[1]`) in the matrix. If no value is stored at the location, inserts a default constructed value at the location and returns a reference to it. - -### Parameters -`index` - Location of the matrix element - -### Return value -A reference to the scalar value at location (`index[0]`, `[index[1]`). - -### Complexity -Implementation defined - -## `grb::matrix::at` -```cpp -scalar_reference at(grb::index index); -const_scalar_reference at(grb::index index) const; -``` - -Returns a reference to the scalar value stored at location (`index[0]`, `index[1]`) in the matrix. If no value is stored at the location, throws the exception `grb::out_of_range`. - -### Parameters -`index` - Location of the matrix element - -### Return value -A reference to the scalar value at location (`index[0]`, `[index[1]`). - -### Complexity -Implementation defined - -### Exceptions -If no element exists at location (`index[0]`, `index[1]`), throws the exception `grb::out_of_range`. diff --git a/markdown/matrix_traits.md b/markdown/matrix_traits.md deleted file mode 100644 index 2211143..0000000 --- a/markdown/matrix_traits.md +++ /dev/null @@ -1,54 +0,0 @@ -### `grb::matrix_value_t` - -```cpp -template -using matrix_value_t = std::ranges::range_value_t; -``` - -Obtain the value type of the matrix-like type `Matrix`. Equal to `std::ranges::range_value_t`. - -### `grb::vector_value_t` - -```cpp -template -using vector_value_t = std::ranges::range_value_t; -``` - -Obtain the value type of the vector-like type `Vector`. Equal to `std::ranges::range_value_t`. - -### `grb::matrix_scalar_t` - -```cpp -template -using matrix_scalar_t = std::remove_cvref_t>::type>; -``` - -Obtain the type of scalar values stored in the matrix-like type `Matrix`. Equal to the second element stored in the matrix's tuple-like value type. - -### `grb::vector_scalar_t` - -```cpp -template -using vector_scalar_t = std::remove_cvref_t>::type>; -``` - -Obtain the type of scalar values stored in the vector-like type `Vector`. Equal to the second element stored in the vector's tuple-like value type. - -### `grb::matrix_key_t` - -```cpp -template -using matrix_key_t = std::remove_cvref_t>::type>; -``` - -Obtain the key type of the matrix. This is a tuple-like type used to store each scalar value's row and column indices. - -### `grb::matrix_index_t` - -```cpp -template -using matrix_index_t = std::remove_cvref_t>::type>; -``` - -Obtain the integer-like type used to store matrix indices. - diff --git a/markdown/max.md b/markdown/max.md deleted file mode 100644 index 2bc1610..0000000 --- a/markdown/max.md +++ /dev/null @@ -1,110 +0,0 @@ -## `grb::max` - -```cpp -template -struct max; -``` - -`grb::max` is a binary operator that returns the larger of two arguments. -When both input arguments have integral types, `std::cmp_less` is used for comparison. When one or both arguments have non-integral types, `operator<` is used for comparison. -It forms a monoid on arithmetic types. - -### Specializations -Specialization | Description ------ | ----- -`max` | deduces argument and return types -`max` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the larger of two arguments - -#### `grb::max::operator()` - -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the larger of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to take the max of - -#### Return Value - -The larger of `lhs` and `rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator<()` operation throws exceptions - -#### Monoid Traits - -`grb::max` forms a monoid on any arithmetic type `A` with the identity value -`std::min(std::numeric_limits
::lowest(), -std::numeric_limits::infinity())`, -as long as `T`, `U`, and `V` are equal to void or `A`. - -### Specialization Details -#### `grb::max` -```cpp -template <> -struct max; -``` -Version of `grb::max` with both arguments and return types deduced. - -#### `grb::max::operator()` - -```cpp -template -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::cmp_less(std::numeric_limits::max(), - std::numeric_limits::max()), - U, T - >; - -template -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::numeric_limits::max() < std::numeric_limits::max(), - U, T - > -requires(!(std::is_integral_v && std::is_integral_v)); -``` - -#### `grb::max` - -```cpp -template -struct max; -``` - -Version of `grb::max` with explicit types for the arguments, but return type deduced. - -#### `grb::max::operator()` - -```cpp -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::cmp_less(std::numeric_limits::max(), - std::numeric_limits::max()), - U, T - >; - -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::numeric_limits::max() < std::numeric_limits::max(), - U, T - > -requires(!(std::is_integral_v && std::is_integral_v)); -``` diff --git a/markdown/metadata.md b/markdown/metadata.md deleted file mode 100644 index d932d01..0000000 --- a/markdown/metadata.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -numbersections: true -documentclass: book -classoption: - - oneside - -header-includes: | - ---- - ---- diff --git a/markdown/min.md b/markdown/min.md deleted file mode 100644 index 8b05db8..0000000 --- a/markdown/min.md +++ /dev/null @@ -1,111 +0,0 @@ -## `grb::min` - -```cpp -template -struct min; -``` - -`grb::min` is a binary operator that returns the smaller of two arguments. -using `operator<` for comparison. -When both input arguments have integral types, `std::cmp_less` is used for comparison. When one or both arguments have non-integral types, `operator<` is used for comparison. -It forms a monoid on arithmetic types. - -### Specializations -Specialization | Description ------ | ----- -`min` | deduces argument and return types -`min` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the smaller of two arguments - -#### `grb::min::operator()` - -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the smaller of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to take the min of - -#### Return Value - -The smaller of `lhs` and `rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator<()` operation throws exceptions - -#### Monoid Traits - -`grb::min` forms a monoid on any arithmetic type `A` with the identity value -`std::max(std::numeric_limits::max(), std::numeric_limits::infinity())`, -as long as `T`, `U`, and `V` are equal to void or `A`. - -### Specialization Details -#### `grb::min` -```cpp -template <> -struct min; -``` -Version of `grb::min` with both arguments and return types deduced. - -#### `grb::min::operator()` - -```cpp -template -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::cmp_less(std::numeric_limits::lowest(), - std::numeric_limits::lowest()), - U, T - >; - -template -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::numeric_limits::lowest() < std::numeric_limits::lowest(), - U, T - > -requires(!(std::is_integral_v && std::is_integral_v)); -``` - -#### `grb::min` - -```cpp -template -struct min; -``` - -Version of `grb::min` with explicit types for the arguments, but return type deduced. - -#### `grb::min::operator()` - -```cpp -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::cmp_less(std::numeric_limits::lowest(), - std::numeric_limits::lowest()), - U, T - >; - -constexpr auto operator()(const T& a, const U& b) const - -> std::conditional_t< - std::numeric_limits::lowest() < std::numeric_limits::lowest(), - U, T - > -requires(!(std::is_integral_v && std::is_integral_v)); -``` diff --git a/markdown/minus.md b/markdown/minus.md deleted file mode 100644 index e196869..0000000 --- a/markdown/minus.md +++ /dev/null @@ -1,83 +0,0 @@ -## `grb::minus` - -```cpp -template -struct minus; -``` - -`grb::minus` is a binary operator that subtracts two values. - -### Specializations -Specialization | Description ------ | ----- -`minus` | deduces argument and return types -`minus` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the difference of the two arguments - -#### `grb::minus::operator()` - -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the difference of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to subtract - -#### Return Value - -The result of `lhs - rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator-()` operation throws exceptions - -#### Monoid Traits - -`grb::minus` does not form a monoid for arithmetic types. - -### Specialization Details -#### `grb::minus` -```cpp -template <> -struct minus; -``` -Version of `grb::minus` with both arguments and return types deduced. - -#### `grb::minus::operator()` - -```cpp -template -constexpr auto operator()(T&& lhs, U&& rhs) const - -> decltype(std::forward(lhs) - std::forward(rhs)); -``` - -#### `grb::minus` - -```cpp -template -struct minus; -``` - -Version of `grb::minus` with explicit types for the arguments, but return type deduced. - -#### `grb::minus::operator()` - -```cpp -constexpr auto operator()(const T& lhs, const U& rhs) const - -> decltype(lhs - rhs); -``` diff --git a/markdown/multiplies.md b/markdown/multiplies.md deleted file mode 100644 index 461c08b..0000000 --- a/markdown/multiplies.md +++ /dev/null @@ -1,84 +0,0 @@ -## `grb::multiplies` - -```cpp -template -struct multiplies; -``` - -`grb::multiplies` is a binary operator. It forms a monoid on arithmetic types. - -### Specializations -Specialization | Description ------ | ----- -`multiplies` | deduces argument and return types -`multiplies` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the product of the two arguments - -#### `grb::multiplies::operator()` - -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the product of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to multiply - -#### Return Value - -The result of `lhs * rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator*()` operation throws exceptions - -#### Monoid Traits - -`grb::multiplies` forms a monoid on any arithmetic type `A` with the identity value `1`, -as long as `T`, `U`, and `V` are equal to void or `A`. - -#### Specialization Details -##### `grb::multiplies` -```cpp -template <> -struct multiplies; -``` -Version of `grb::multiplies` with both arguments and return types deduced. - -##### `grb::multiplies::operator()` - -```cpp -template -constexpr auto operator()(T&& lhs, U&& rhs) const - -> decltype(std::forward(lhs) * std::forward(rhs)); -``` - -##### `grb::multiplies` - -```cpp -template -struct multiplies; -``` - -Version of `grb::multiplies` with explicit types for the arguments, but return type deduced. - -##### `grb::multiplies::operator()` - -```cpp -constexpr auto operator()(const T& lhs, const U& rhs) const - -> decltype(lhs * rhs); -``` diff --git a/markdown/multiply.md b/markdown/multiply.md deleted file mode 100644 index 6518c74..0000000 --- a/markdown/multiply.md +++ /dev/null @@ -1,419 +0,0 @@ -## Multiply - -The function `grb::multiply` in GraphBLAS is used to multiply a matrix times a matrix, a matrix times a vector, or a vector times a matrix, depending on the types of the input arguments. - -#### Matrix Times Matrix -```cpp -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskMatrixRange M = grb::full_matrix_mask<> -> -multiply_result_t -multiply(A&& a, (1) - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - -template , grb::matrix_scalar_t> Combine = grb::multiplies<>, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce = grb::plus<>, - MaskMatrixRange M = grb::full_matrix_mask<>, - MutableMatrixRange> C, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, -> -void multiply(C&& c, (2) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); - -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskMatrixRange M = grb::full_matrix_mask<> -> -multiply_result_t -multiply(ExecutionPolicy&& policy, (3) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskMatrixRange M = grb::full_matrix_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableMatrixRange> C -> -void multiply(ExecutionPolicy&& policy, (4) - C&& c, - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); -``` - -#### Matrix Times Vector - -```cpp -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<> -> -mutiply_result -multiply(A&& a, (5) - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - - -template , grb::vector_scalar_t> Combine = grb::multiplies<>, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce = grb::plus<>, - MaskVectorRange M = grb::full_vector_mask<>, - MutableVectorRange> C, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right<> -> -void multiply(C&& c, (6) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); - -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<> -> -mutiply_result -multiply(A&& a, (7) - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void multiply(C&& c, (8) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); -``` - -#### Vector Times Vector - -```cpp -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, -> -mutiply_result -multiply(A&& a, (9) - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}); - -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - std::assignable_from> C -> -void multiply(C&& c, (10) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); - -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, -> -mutiply_result -multiply(ExecutionPolicy&& policy, (11) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}); - -template , grb::vector_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - std::assignable_from> C -> -void multiply(ExecutionPolicy&& policy, (12) - C&& c, - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); -``` - -#### Vector Times Matrix - -```cpp -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<> -> -mutiply_result -multiply(A&& a, (13) - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - -template , grb::matrix_scalar_t> Combine = grb::multiplies<>, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce = grb::plus<>, - MaskVectorRange M = grb::full_vector_mask<>, - MutableVectorRange> C, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, -> -void multiply(C&& c, (14) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); - -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<> -> -mutiply_result -multiply(ExecutionPolicy&& policy, (15) - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}); - -template , grb::matrix_scalar_t> Combine, - BinaryOperator, - grb::combine_result_t, - grb::combine_result_t> Reduce, - MaskVectorRange M = grb::full_vector_mask<>, - BinaryOperator, - grb::combine_result_t> Accumulate = grb::take_right, - MutableVectorRange> C -> -void multiply(ExecutionPolicy&& policy, (16) - C&& c, - A&& a, - B&& b, - Reduce&& reduce = Reduce{}, - Combine&& combine = Combine{}, - M&& mask = M{}, - Accumulate&& acc = Accumulate{}, - bool merge = false); -``` - -Behavior is non-deterministic if `reduce` is not associative or not commutative. - -### Parameters -`policy` - the execution policy to use - -`a` - the left-hand side of the product being computed - -`b` - the right-hand side of the product being computed - -`reduce` - a binary operator - -`combine` - a binary operator - -`mask` - write mask used to determine which elements of the output will be computed - -`c` - if given, the output object to which to write the result - -`acc` - the accumulator used to accumulate partial results into the output object - -`merge` - whether to merge in values from `c` outside of the write area indicated by `mask` - -#### Type Requirements -- `A` must meet the requirements of `MatrixRange` (1-8) or `VectorRange` (9-16) - -- `B` must meet the requirements of `MatrixRange` (1-4,13-16) or `VectorRange` (5-12) - -- `Reduce` must meet the requirements of `BinaryOperator, grb::combine_result_type_t, grb::combine_result_type_t>` - -- `Combine` must meet the requirements of `BinaryOperator, grb::container_value_t>` - -- `M` must meet the requirements of `MaskMatrixRange` (1-8) or `VectorMaskRange` (9-16) - -### Return Value - -If the output matrix or vector argument, `c`, is supplied, no value is returned. - -__NOTE: `combine_result_t is actually incorrect here. Should be result of reduction.__ - -If `c` is not supplied as an argument, returns the result of the multiplication. - -(1) - A GraphBLAS matrix with shape `a.shape()[0]` by `b.shape()[1]` - -(3) - A GraphBLAS vector with shape `a.shape()[0]` - -(5) - `combine_result_t` - -(7) - A GraphBLAS vector with shape `b.shape()[1]` - -In the case that a GraphBLAS matrix or vector is returned, its scalar type is -`combine_result_t`, and its index type is equal to either -`grb::matrix_index_t` or `grb::matrix_index_t`, whichever one has the larger -`std::numeric_limits::max()`. -An element of the result at index location `index` will only be computed if -a scalar value equal to `true` when converted to `bool` exists in `mask`, that is -`grb::find(mask, index) != grb::end(mask) && bool(grb::get<1>(*grb::find(mask, index)))`. - -##### Matrix Times Matrix -A generalized matrix times matrix multiplication is performed, as defined in the -[GraphBLAS Math Specification](https:://github.com/GraphBLAS/graphblas-api-math). -Each element of the output is produced by combing the elements in corresponding indices of a row of `a` -and column of `b` and using `reduce` to perform a reduction to a single value. - -##### Matrix Times Vector -A generalized matrix times vector multiplication is performed, as defined in the -[GraphBLAS Math Specification](https:://github.com/GraphBLAS/graphblas-api-math). -Each element of the output vector is produced by combining elements in each row -of `a` with the corresponding elements of the vector `b` and using `reduce` to -perform a reduction of these to a single value in the output vector. - -##### Vector Times Vector -A generalized dot product is performed, as defined in the -[GraphBLAS Math Specification](https:://github.com/GraphBLAS/graphblas-api-math). -The corresponding elements of vectors `a` and `b` are combined and reduced into -a single value using `reduce`. - -##### Vector Times Matrix -A generalized matrix times vector multiplication is performed, as defined in the -[GraphBLAS Math Specification](https:://github.com/GraphBLAS/graphblas-api-math). -Each element of the output vector is produced by combining elements in each column -of `b` with the corresponding elements of the vector `a` and using `reduce` to -perform a reduction of these to a single value in the output vector. - -### Complexity -Complexity is implementation-defined. - -### Exceptions -The exception `grb::invalid_argument` may be thrown if any of the following conditions occur: - -##### Matrix Times Matrix -- The dimensions of the matrices being multiplied are incompatible, that is `a.shape()[1] != b.shape()[0]`. -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape()[0] < a.shape()[0] || mask.shape()[1] < b.shape()[1]` -- The dimensions of the output matrix, if provided, are incompatible, that is `c.shape()[0] != a.shape()[0] || c.shape()[1] != b.shape()[1]`. - -##### Matrix Times Vector -- The dimensions of the matrix and vector being multiplied are incompatible, that is `a.shape()[1] != b.shape()`. -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape() < a.shape()[0]` -- The dimensions of the output vector, if provided, are incompatible, that is `c.shape() != a.shape()[0]`. - -##### Vector Times Vector -- The dimensions of the vectors being multiplied are incompatible, that is `a.shape() != b.shape()`. -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape() < a.shape()[0]` -- The dimensions of the output vector, if provided, are incompatible, that is `c.shape() != a.shape()[0]`. - -##### Vector Times Matrix -- The dimensions of the matrix and vector being multiplied are incompatible, that is `a.shape() != b.shape()[0]`. -- The dimensions of the mask are smaller than the dimensions of the output, that is `mask.shape() < b.shape()[1]` -- The dimensions of the output vector, if provided, are incompatible, that is `c.shape() != b.shape()[1]`. - -If the algorithm fails to allocate memory, `std::bad_alloc` is thrown. - -### Notes - -### Example diff --git a/markdown/notes/backend_matrix_notes.md b/markdown/notes/backend_matrix_notes.md deleted file mode 100644 index 2512262..0000000 --- a/markdown/notes/backend_matrix_notes.md +++ /dev/null @@ -1,38 +0,0 @@ -# Notes on grb::csr_matrix design - -## *WARNING* These notes are specific to the rgri backend implementation - -```cpp -template > -class grb::csr_matrix; -``` - -## Member Types -Member Type | Definition ------ | ----- -`?` | `T`, the type of elements stored in the matrix -`index_type` | `I`, an integer type used to store matrix indices -`value_type` | `grb::matrix_entry`, a tuple-like type storing copies of the indices and the stored element -`size_type` | A large unsigned integer type, usually `std::size_t` -`difference_type` | A large signed integer type, usually `std::ptrdiff_t` -`allocator_type` | `Allocator` -`iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `reference` [1] -`const_iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `const_reference` [1] -`reference` | `grb::matrix_reference` -`const_reference` | `grb::matrix_reference` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs matrix -`begin()` | Returns iterator to beginning of container -`end()` | Returns iterator to one past last element in container -`insert(first, last)` | Insert range of elements -`insert(elem)` | Inserts single element -`private assign_tuples` | Assigns state to sorted tuples -`find(index)` | Finds index in matrix - -## Notes -[1] Iterator type may vary based on backend storage type. Most will likely provide `std::random_access_iterator`. Dense and COO are `std::random_access_iterator`, as are CSR and COO, with the exception that pointer addition and subtraction are bound by *O(m)* and *O(n)*, respectively, although they are likely to be *O(1)*. diff --git a/markdown/notes/matrix_notes.md b/markdown/notes/matrix_notes.md deleted file mode 100644 index 95e5ddf..0000000 --- a/markdown/notes/matrix_notes.md +++ /dev/null @@ -1,115 +0,0 @@ -# Notes on grb::matrix design - -```cpp -template > -class grb::matrix; -``` - -## Member Types -Member Type | Definition ------ | ----- -`?` | `T`, the type of elements stored in the matrix -`index_type` | `I`, an integer type used to store matrix indices -`value_type` | `grb::matrix_entry`, a tuple-like type storing copies of the indices and the stored element -`size_type` | A large unsigned integer type, usually `std::size_t` -`difference_type` | A large signed integer type, usually `std::ptrdiff_t` -`allocator_type` | `Allocator` -`iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `reference` [1] -`const_iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `const_reference` [1] -`reference` | `grb::matrix_reference` -`const_reference` | `grb::matrix_reference` -`hint_type` | `Hint` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs matrix -`begin` | Returns iterator to beginning of container -`end` | Returns iterator to one past last element in container -`insert` | Insert elements -`insert_or_assign` | Inserts or assigns element - -## Method Declarations -```cpp -template > -class grb::matrix { - - matrix(grb::index shape); - template - matrix(R other); - - matrix(); - ~matrix(); - matrix(const csr_matrix&); - matrix(csr_matrix&&); - matrix& operator=(const csr_matrix&); - matrix& operator=(csr_matrix&&); - - size_type size() const noexcept; - grb::index shape() const noexcept; - - iterator begin() noexcept; - iterator end() noexcept; - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - - template - void insert(InputIt first, InputIt last); - - std::pair insert(value_type&& value); - - template - std::pair insert_or_assign(key_type k, M&& obj); - - iterator find(key_type key) noexcept; - const_iterator find(key_type key) const noexcept; -}; -``` - -## Comparison -Member Type | Value for `unordered_map` | Value for `grb::matrix` | Notes ----- | ---- | ---- | ---- -`key_type` | `std::pair` | `grb::index` | `grb::index` behaves like `std::pair`, but also supports `operator[]`, which is v. convenient -`map_type` | `T` | `T` | Type of stored elements -`?` | `T` | `T` | What we call `map_type` in `grb::matrix` -`index_type` | `I` | `I` | Integral type used to store indices -`value_type` | `std::pair, T>` | `grb::matrix_entry` | `grb::matrix_entry` behaves like `std::pair, T>`, but adds some convenience functions -`reference` | `std::pair, T>&` | `grb::matrix_reference` | `grb::matrix_reference` behaves like `std::pair, T>&` (allows obtaining a reference to value, copies of indices) -`const_reference` | `const std::pair, T>&` | `grb::matrix_reference` | `grb::matrix_reference` behaves like `const std::pair, T>&` (allows obtaining a constant reference to value, copies of indices) - -## Notes -[1] Iterator type may vary based on backend storage type. Most will likely provide `std::random_access_iterator`. Dense and COO are `std::random_access_iterator`, as are CSR and COO, with the exception that pointer addition and subtraction are bound by *O(m)* and *O(n)*, respectively, although they are likely to be *O(1)*. - -# Notes on grb::index -```cpp -template -struct grb::index; -``` - -## Description -`grb::index` is a pair-like class that stores row and column indices associated with a matrix element. - -`T` must fulfill the concept `std::integral`. - -## Template Parameters -`T` - an integral type used to store indices. - -## Member Types -Member Type | Definition ------ | ----- -`index_type` | `T`, an integer type used to store matrix indices -`first_type` | `T`, an integer type used to store matrix indices -`second_type` | `T`, an integer type used to store matrix indices - -## Member Objects -Member Name | Type ------ | ----- -`first` | `T` -`second` | `T` - diff --git a/markdown/notes/sparse_storage_survey.md b/markdown/notes/sparse_storage_survey.md deleted file mode 100644 index 1fc4499..0000000 --- a/markdown/notes/sparse_storage_survey.md +++ /dev/null @@ -1,22 +0,0 @@ -# Survey of Sparse Matrix Formats -Name | Abbr. | Description | Row Iter. | Col. Iter. | Random Access ------ | ----- | ----- | ----- | ----- | ----- -Compressed sparse row | CSR | | X | | O(n)[^1] -Compressed sparse column | CSC | | | X | O(m)[^2] -Coordinate | COO | Many variants: unsorted, sorted, hash table | ? | ? | O(nnz), O(log(nnz)), O(1) -Diagonal | DIA | Store dense diagonals | | | O(1) -Jagged Diagonal | JDS | Remove zeros, then store dense diagonals | | | -Doubly compressed row | DCSR | CSR, but rowptr array is a sparse vector | X | | O(log(m) + n)[^3] -Doubly compressed column | DCSC | CSC, but colptr array is a sparse vector | | X | O(log(n) + m)[^4] -Block compressed row | BCSR | Sparse storage of dense blocks | | | O(1) -Dense storage | - | Dense matrix + boolean map | X | X | O(1) - -Above we assume a matrix with `m` rows and `n` columns containing `nnz` stored values. So O(n) is bound by the number of columns and O(nnz) by the number of stored values. - -[^1]: CSR becomes O(log(n)) if rows are sorted - -[^2]: CSC becomes O(log(m)) if columns are sorted - -[^3]: Assumes sparse `row_ptr` vector sorted. DCSR bcomes O(log(m) + log(n)) if rows are also sorted, O(m + n) if neither are sorted - -[^4]: Assumes sparse `column_ptr` vector sorted. DCSC becomes O(log(n) + log(m)) if columns are also sorted, O(n + m) if neither are sorted diff --git a/markdown/notes/vector_notes.md b/markdown/notes/vector_notes.md deleted file mode 100644 index ec47f5c..0000000 --- a/markdown/notes/vector_notes.md +++ /dev/null @@ -1,76 +0,0 @@ -# Notes on grb::vector design - -```cpp -template > -class grb::vector; -``` - -## Member Types -Member Type | Definition ------ | ----- -`?` | `T`, the type of elements stored in the vector -`index_type` | `I`, an integer type used to store vector indices -`value_type` | `grb::vector_entry`, a tuple-like type storing copies of the index and the stored element -`size_type` | A large unsigned integer type, usually `std::size_t` -`difference_type` | A large signed integer type, usually `std::ptrdiff_t` -`allocator_type` | `Allocator` -`iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `reference` [1] -`const_iterator` | Fulfills `std::forward_iterator`, with `operator*` returning `const_reference` [1] -`reference` | `grb::vector_reference` -`const_reference` | `grb::vector_reference` -`hint_type` | `Hint` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs vector -`begin` | Returns iterator to beginning of container -`end` | Returns iterator to one past last element in container -`insert` | Insert elements -`insert_or_assign` | Inserts or assigns element - -## Method Declarations -```cpp -template > -class grb::vector { - - vector(index_type shape); - - vector(); - ~vector(); - vector(const vector&); - vector(vector&&); - vector& operator=(const vector&); - vector& operator=(vector&&); - - size_type size() const noexcept; - index_type shape() const noexcept; - - iterator begin() noexcept; - iterator end() noexcept; - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - - template - void insert(InputIt first, InputIt last); - - std::pair insert(value_type&& value); - - template - std::pair insert_or_assign(key_type k, M&& obj); - - // NOTE: Should be generalized, not just T& - T& operator[](index_type index); - const T& operator[](index_type index) const; - - iterator find(key_type key) noexcept; - const_iterator find(key_type key) const noexcept; -}; -``` - diff --git a/markdown/ops_ewise.md b/markdown/ops_ewise.md deleted file mode 100644 index 6dc724c..0000000 --- a/markdown/ops_ewise.md +++ /dev/null @@ -1,50 +0,0 @@ -# Element-Wise Operations - -## Element-wise multiplication - -```cpp -template -auto ewise_mult(CMatrixType&& c, AMatrixType&& a, BMatrixType&& b, Fn&& fn, Accumulator&& acc, MaskType&& mask = MaskType()); - -template -auto ewise_mult(AMatrixType&& a, BMatrixType&& b, Fn&& fn, MaskType&& mask = MaskType()); -``` ---- - -Need to add vector versions - ---- - -## Element-wise addition - -```cpp -template -auto ewise_add(CMatrixType&& c, AMatrixType&& a, BMatrixType&& b, Fn&& fn, Accumulator&& acc, MaskType&& mask = MaskType()); - -template -auto ewise_add(AMatrixType&& a, BMatrixType&& b, Fn&& fn, MaskType&& mask = MaskType()); -``` ---- - -Need to add vector versions - ---- - - -### Examples diff --git a/markdown/ops_mxm.md b/markdown/ops_mxm.md deleted file mode 100644 index 159e73c..0000000 --- a/markdown/ops_mxm.md +++ /dev/null @@ -1,228 +0,0 @@ -# Matrix-matrix multiplication: `mxm` - -_TODO: this should probably be brought under "operations" as a header, to align with the way I'm writing multiply. Basically all the headings would need to go down one level. I'll take a look at this after I've worked out more of multiply._ - -Multiplies two GraphBLAS matrices using the operators and identity defined by a GraphBLAS semiring. An optional accumulator and write mask can also be specified. The result is stored in third GraphBLAS matrix. - -```cpp - // Attempt at using the concepts - // First some dependencies (these go somewhere else) - template - U no_accumulate(T&& t, U&& u) { // move definition somewhere else - return u; - } - - template - using matrix_scalar_type_t = typename std::remove_cvref_t::scalar_type; - - template - using grb::binop_result_type_t = decltype( - std::declval()(grb::matrix_scalar_type_t, - grb::matrix_scalar_type_t)); - - // Binary Operator overload - template, - grb::matrix_scalar_type_t> Combine, - BinaryOperator, - grb::binop_result_type_t, - grb::binop_result_type_t> Reduce, - BinaryOperator, - grb::binop_result_type< - Reduce, - grb::binop_result_type_t, - grb::binop_result_type_t>, - grb::matrix_value_type_t> Accumulate = grb::no_accumulate, - MutableMatrixRange< - grb::binop_result_type_t< - Accumulate, - grb::matrix_scalar_type_t, - grb::binop_result_type< - Reduce, - grb::binop_result_type_t, - grb::binop_result_type_t>> C, - MaskMatrixRange Mask = grb::no_mask> // or grb::full_mask - void mxm(C &c, // use &&? - A &&a, - B &&b, - Reduce &&reduce, - Combine &&combine, - Accumulate &&accum = Accumulator(), - Mask &&m = Mask(), - bool replace = false); // or use an enumerated type? - -``` - - -```cpp - // Binary Operator overload - template // instead of full_mask - void mxm(CMatrixType &C, // use &&? - ReduceType &&reduce, // In general, what is the style - CombineType &&combine, // to document [IN] vs. [IN,OUT] - AMatrixType const &&A, // intentions - BMatrixType const &&B, - AccumulatorType &&accum = AccumulatorType(), - MaskType const &&Mask = MaskType(), - bool replace = false); // or use an enumerated type? -``` - ------ - - -```cpp - // Semiring operator overload - template // instead of full_mask - void mxm(CMatrixType &C, - SemiringType &&op, - AMatrixType const &&A, - BMatrixType const &&B, - AccumulatorType &&accum = AccumulatorType(), - MaskType const &&Mask = MaskType(), - bool replace = false); // or use an enumerated type? -``` - ------ - -```cpp - // Overload that returns output - template, // default? yes or no - BinaryOp CombineType = std::multiplies<>, // default? yes or no; - MaskMatrixView MaskType = std::no_mask> // instead of full_mask? - auto mxm(AMatrixType &&A, // mxm(..) or multiply(..)? - BMatrixType &&B, - ReduceType &&reduce = ReduceType(), - CombineType &&combine = CombinType(), // or CombineFn - MaskType &&Mask = MaskType(), // or grb::no_mask() - bool replace = false); // or use an enumerated type? -``` - ------ - -## Notes - -(any notes go here) - -TODO list -- Overload on operator: Should we have two overloads: pair of binary operators AND a semiring? (vote against latter) -- Function name: Should the overload that does not have an in/out parameter (and no accumulator) also be called `mxm`? RGRI calls it `multiply` - - mxm is legacy (known), C++ allows overloading -- Mask: Should we move mask to end so that it can be defaulted? - - Pro: belongs with replace flag - - Pro: matches rgri parameter order for multiply - - is `no_mask` the best default name? -- replace: Should `replace` flag be a boolean or enumerated type -- Times: Tim does not like `Combine`. What should it be called -- Plus: Scott likes `Reduce`...Tim does not. -- Parameter Order: Should we move operators to after the input containers or keep before - - Currently the third overload is not a consistent order with either of the first two. -- Accumulator - - Should we move the optional accumulator to the end as well so that it can be defaulted as well? - - is `no_accumulate` the best default name? -- Type and concept naming conventions - - Type: MatrixType vs matrix_t - - Concept: MatrixView vs matrix_view vs matrix_view_c - -## Parameters -Parameter | In/Out | Definition ------ | ----- | ----- -`C` | In/Out | An existing GraphBLAS matrix. On input, the matrix provides values that may be accumulated with the result of the matrix product, or values that are merged with masked results. -`op` | In | A semiring containing a binary map operator and a commutative monoid operator for reduction. -`reduce` | In | A commutative monoid or a commutative binary operator with type restrictions(?) for reduction. The signature of the function should be equivalent to the following:
`T fn(T const &c1, T const &c2);` -`combine` | In | A binary times/multiplies/map operator. The signature of the function should be equivalent to the following:
`T fn(U const &a, V const &b);` -`A` | In | The left-hand input matrix (view, const). Using the transpose of the matrix may be accomplished by passing `grb::transpose(A)`. -`B` | In | The right-hand input matrix (view, const). Using the transpose of the matrix may be accomplished by passing `grb::transpose(B)`. -`accum` | In | An optional accumulation binary operator. If assignment rather than accumulation is desired, pass `grb::no_accumulator`(`grb::assign`?) -`Mask` | In | An optional "write" mask (or mask view) that controls which results from this operation are stored into the output matrix `C`. The mask dimensions must match thoese of the matrix `C`. If no masking is desired, pass `grb::no_mask` (or `grb::full_mask`). To use the structure of a matrix as the mask, call with `grb::structure(Mask)`. To complement the logic of the mask, call with `grb::complement(Mask)` -`replace` | In | If a non-full mask is specified this parameter controls the prior contents of C that is 'masked out'. If `true` is specified the elements in `C` are cleared (replace semantics); otherwise `false` leaves these elements unmodified (merge semantics). - -### Type requirements - -Method | Description ------ | ----- -`CMatrixType`/`C_matrix_t` | Must meet the requirements of `MatrixView`/`matrix_c` (?) -`AMatrixType`/`A_matrix_t`, `BMatrixType`/`B_matrix_t` | Must meet the requirements of `ConstMatrixView`/`const_matrix_view_c` -`MaskType`/`mask_t` | Must meet the requirements of `MaskMatrixView`/`mask_matrix_view_c` (they are all const) [Note: the elements of the mask view must be convertible to bool.] -`AccumulatorType`/`accum_op_t` | Must meet the requirements of `BinaryOp`/`binary_op_c` -`SemiringType`/`semiring_op_t` | Must meet the requirements of `SemiringOp`/`semiring_op_c` (is this a thing?) -`ReduceType` or `ReduceFn`/`reduce_op_t` | Must meet the requirements `CommutativeMonoid`/`commutative_monoid_c` (or must `Monoid`/`monoid_c` or `GraphBLASMonoid`/`graphblas_monoid_c`?) -`MapType` or `MapFn` or `CombineType` / `combine_op_t` | Must meet the requirements of `BinaryOp`/`binary_op_c` (is this a thing?) - - -## Return value - -The first two overloads of `mxm` do not have a return value. In blocking mode, the operation has completed successfully on return. In non-blocking mode, this indicates that the compatibility tests on dimensions \scott{and domains for the input arguments passed successfully}. Either way, output matrix {\sf C} is ready to be used in the next method of the sequence. - -The return value of (third) `mxm` (or `multiply`) variant is a GraphBLAS matrix of dimensions `A.nrows() x B.ncols()`. The scalar type is the output type of the `reduce` operator. - -## Exceptions - -- `grb::bad_alloc` any allocation failure (is there `std::bad_alloc` instead?) -- `grb::panic_error` (execution error, `grb::runtime_error`) unknown internal error -- `grb::invalid_object` (execution error, `grb::runtime_error`) any execution mode; whenever any of the graphblas objects is in an invalid state. -- `grb::dimension_mismatch` (API error, logic error) mask or matrix dimensions are incompatible. - -## Description - -Does the C++ specification need to have a long, largely duplicative description of what can be found in the C API description? - -Carries out matrix multiplication using reduce and combine operators or a semiring (containing this pair) of in put matrices A and B, optionally accumulates using the accum operator with the output matrix C, and writes this results back into the C matrix under control of the optional write mask and replace flag. ...according to the math provided in the math specification. - -## Examples - -```c++ - grb::Matrix A({5, 10}); - grb::Matrix B({10, 5}); - grb::Matrix C5({5, 5}); - grb::Matrix M5({5, 5}); - grb::Matrix C10({10, 10}); - grb::Matrix M10({10, 10}); - - // ... fill the matrices - - // using no matrix views - grb::mxm(C5, grb::NoAccumulate{} - grb::PlusTimesSemiring{}, A, B, - M5, false); //grb::MERGE); - - // using all possible matrix views - grb::mxm(C10, grb::NoAccumulate{}, - grb::PlusTimesSemiring{}, grb::transpose(A), grb::transpose(B), - grb::complement(grb::structure(M10)), true); //grb::REPLACE); - - // the alternate map-reduce form - // using all possible matrix views - grb::mxm(C10, grb::NoAccumulate{}, - grb::Plus{}, grb::Times{}, - grb::transpose(A), grb::transpose(B), - grb::complement(grb::structure(M10)), true); // grb::REPLACE); - - // the alternate map-reduce form using lambdas - // using all possible matrix views - grb::mxm(C10, grb::NoAccumulate{}, - [&](auto &&c1, auto &&c2) { return c1 + c2; }, // reduce (is && right?) - [&](auto &&a, auto &&b) { return a * b; }, // combine (is && right?) - grb::transpose(A), grb::transpose(B), - grb::complement(grb::structure(M10)), true); //grb::REPLACE); - - // multiply alternative - auto C = grb::mxm(grb::transpose(A), grb::transpose(B), - [&](auto const &c1, auto const &c2) {return c1+c2;}, // reducer - [&](auto const &a, auto const &b) {return a * b;}, // mapper - grb::complement(grb::structure(M10)), true); //grb::REPLACE); -``` - diff --git a/markdown/plus.md b/markdown/plus.md deleted file mode 100644 index 031e552..0000000 --- a/markdown/plus.md +++ /dev/null @@ -1,83 +0,0 @@ -## `grb::plus` - -```cpp -template -struct plus; -``` - -`grb::plus` is a binary operator. It forms a monoid on arithmetic types. - -### Specializations -Specialization | Description ------ | ----- -`plus` | deduces argument and return types -`plus` | deduces return type based on `T` and `U` - - -### Template Parameters -`T` - Type of the left hand argument of the operator - -`U` - Type of the right hand argument of the operator - -`V` - Return type of the operator - -### Methods -Method | Description ------ | ----- -`operator()` | returns the sum of the two arguments - -#### `grb::plus::operator()` -```cpp -constexpr V operator()( const T& lhs, const U& rhs ) const; -``` - -Returns the sum of `lhs` and `rhs`. - -#### Parameters - -`lhs`, `rhs` - values to sum - -#### Return Value - -The result of `lhs + rhs`. - -#### Exceptions - -May throw exceptions if the underlying `operator+()` operation throws exceptions - -#### Monoid Traits - -`grb::plus` forms a monoid on any arithmetic type `A` with the identity value `0`, -as long as `T`, `U`, and `V` are equal to void or `A`. - -### Specialization Details -#### `grb::plus` -```cpp -template <> -struct plus; -``` -Version of `grb::plus` with both arguments and return types deduced. - -#### `grb::plus::operator()` - -```cpp -template -constexpr auto operator()(T&& lhs, U&& rhs) const - -> decltype(std::forward(lhs) + std::forward(rhs)); -``` - -#### `grb::plus` - -```cpp -template -struct plus; -``` - -Version of `grb::plus` with explicit types for the arguments, but return type deduced. - -#### `grb::plus::operator()` - -```cpp -constexpr auto operator()(const T& lhs, const U& rhs) const - -> decltype(lhs + rhs); -``` diff --git a/markdown/preamble.tex b/markdown/preamble.tex deleted file mode 100644 index 1499ec4..0000000 --- a/markdown/preamble.tex +++ /dev/null @@ -1,4 +0,0 @@ -\usepackage{longtable} -\setlength{\LTleft}{0em} - -\newcommand{\scott}[1]{{{\color{red}[Scott: #1]}}} diff --git a/markdown/read_matrix.md b/markdown/read_matrix.md deleted file mode 100644 index c13e2e3..0000000 --- a/markdown/read_matrix.md +++ /dev/null @@ -1,44 +0,0 @@ -## `read_matrix` - - -```cpp - -template > -grb::matrix -read_matrix(std::string file_path); -``` - -Constructs a new GraphBLAS matrix based on the contents of a file. - -## Template Parameters -`T` - type of scalar values stored in matrix - -`I` - type of matrix indices - -`Hint` - compile-time hint for backend storage format. - -`Allocator` - allocator type - -### Parameters -`file_path` - string holding the file path of the matrix to be read - -### Return Value - -Returns a GraphBLAS matrix whose dimensions and contents correspond to the -file located at `file_path`. - -### Complexity -Complexity is implementation-defined. - -### Exceptions -- If the file at `file_path` cannot be read, the exception `grb::matrix_io::file_error` is thrown. -- If the file at `file_path` is recognized as an unsupported format, the exception `grb::matrix_io::unsupported_file_format` is thrown. -- Calls to `Allocator::allocate` may throw. - -### Notes -GraphBLAS implementations must define the file formats that they support. Implementations are strongly encouraged to support the MatrixMarket format. - -### Example diff --git a/markdown/title.tex b/markdown/title.tex deleted file mode 100644 index 68ae8da..0000000 --- a/markdown/title.tex +++ /dev/null @@ -1,52 +0,0 @@ -\title{GraphBLAS C++ API Specification\\ -{\large Version \emph{1.0}} -} - -\author{Benjamin Brock, Scott McMillan, Ayd\i{}n Bulu\c{c}, Timothy Mattson, and Jos\'e Moreira} - -\date{Generated on \today} - -\maketitle - -Copyright \copyright\ 2017-2022 Carnegie Mellon University, The Regents -of the University of California, through Lawrence Berkeley National -Laboratory (subject to receipt of any required approvals from the -U.S. Dept. of Energy), the Regents of the University of California -(U.C. Berkeley), Intel Corporation, and International Business Machines -Corporation. - -Any opinions, findings and conclusions or recommendations expressed in -this material are those of the author(s) and do not necessarily reflect -the views of the United States Department of Defense, the United States -Department of Energy, Carnegie Mellon University, the Regents of the -University of California, Intel Corporation, or the IBM Corporation. - -NO WARRANTY. THIS MATERIAL IS FURNISHED ON AN AS-IS BASIS. THE COPYRIGHT -OWNERS AND/OR AUTHORS MAKE NO WARRANTIES OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF -FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED -FROM USE OF THE MATERIAL. THE COPYRIGHT OWNERS AND/OR AUTHORS DO NOT MAKE -ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADE MARK, -OR COPYRIGHT INFRINGEMENT. - -\vspace{1.5cm} - -\vspace{2cm} -%{\Large This version is a definitive release of the GraphBLAS C API -%specification. As of the date of this document, at least two independent -%and functionally complete implementations are available.} - -%{\Large This version is a provisional release of the GraphBLAS C API specification. -%Once two functionally complete reference implementations are available, we -%will remove the "provisional" clause.} - - -\vspace{1.5cm} - - -%[Distribution Statement A] This material has been approved for public release and unlimited distribution. -%Please see Copyright notice for non-US Government use and distribution. - -Except as otherwise noted, this material is licensed under a Creative Commons Attribution 4.0 license (\href{http://creativecommons.org/licenses/by/4.0/legalcode}{http://creativecommons.org/licenses/by/4.0/legalcode}), -and examples are licensed under the BSD License (\href{https://opensource.org/licenses/BSD-3-Clause}{https://opensource.org/licenses/BSD-3-Clause}). - diff --git a/markdown/type_traits.md b/markdown/type_traits.md deleted file mode 100644 index 06290d8..0000000 --- a/markdown/type_traits.md +++ /dev/null @@ -1,82 +0,0 @@ -# Type Traits - -## `grb::monoid_traits` - -```cpp -template -struct monoid_traits; -``` - -The `monoid_traits` template struct provides information about the monoid that -is formed by the commutative binary operator `Fn` on the type `T`. Namely, -it provides a way to retrieve the monoid's identity. - -Users can specialize `monoid_traits` for custom operators, which will make their -identity elements available to GraphBLAS algorithms, possibly enabling optimizations. -The default specialization of `monoid_traits` detects and provides the identity -of the monoid if it has an `identity` method. - -## Template Parameters -`Fn` - type of commutative binary operator - -`T` - type on which `Fn` forms a commutative monoid - -### Member Types -Member Type | Definition | Description ------ | ----- | ----- -`type` | `T` | type of the monoid - -The default specialization has the following member functions: - -### Member Functions -Function | Description ------ | ----- | ----- -`identity` | the identity value of the monoid - -### `grb::monoid_traits::identity` - -```cpp -static constexpr T identity() noexcept; -``` - -Returns the identity of the monoid. - -#### Parameters -None - -#### Complexity -Constant - -#### Exceptions -May not throw exceptions - -#### Possible Implementation - -```cpp -template -static constexpr T grb::monoid_traits::identity() noexcept { - if constexpr(requires { {Fn::identity() } -> std::same_as }) { - return Fn::identity(); - } else if constexpr(requires { {Fn:: template identity()} -> std::same_as }) { - return Fn:: template identity(); - } -} -``` - -### Specializations - -```cpp -template -struct grb::monoid_traits, T>; - -template -struct grb::monoid_traits, T>; -``` - -```cpp -template -struct grb::monoid_traits, T>; - -template -struct grb::monoid_traits, T>; -``` diff --git a/markdown/utilities.md b/markdown/utilities.md deleted file mode 100644 index 0a545bb..0000000 --- a/markdown/utilities.md +++ /dev/null @@ -1,168 +0,0 @@ -# Utilities - -_TODO: need "disablers" for all these CPOs. Also, "converted to its decayed type?"_ - -## `grb::get` - -```cpp -inline constexpr /* unspecified */ get = /* unspecified */; -``` - -#### Call Signature -```cpp -template -requires /* see below */ -constexpr std::tuple_element get(T&& tuple); -``` - -_TODO: we need someone who understands CPOs a little better to understand this._ - -Returns the `I'th` element stored in the tuple-like object `tuple`. - -A call to `grb::get` is expression-equivalent to: - -1) `tuple.get()`, if that expression is valid. -2) Otherwise, any calls to `get(tuple)` found through argument-dependent lookup. -3) Otherwise, `std::get(tuple)`. - -In all other cases, a call to `grb::get` is ill-formed. - -## `grb::size` - -```cpp -template -inline constexpr /* unspecified */ size = std::ranges::size; -``` - -#### Call Signature -```cpp -template -constexpr auto size(T&& t); -``` - -Returns the number of stored values in a GraphBLAS matrix, vector, or other range. -Whenever `grb::size(e)` is valid for an expression `e`, the return type is integer-like. - -A call to `grb::size(t)` is expression-equivalent to: - -1) `t.size()`, if that expression is valid. -2) Otherwise, any calls to `size(t)`, found through argument-dependent lookup. - -In all other cases, a call to `grb::size` is ill-formed. - -## `grb::shape` - -```cpp -template -inline constexpr /* unspecified */ shape = /* unspecified */; -``` - -#### Call Signature -```cpp -template -requires /* see below */ -constexpr auto shape(T&& t); -``` - -Returns the shape of a GraphBLAS object. If `T` fulfills the requirements of `MatrixRange`, then the return type will be a tuple-like type storing two integer-like values, fulfilling the requirements of `TupleLike`, where `I` is the index type of `T`. If `T` fulfills the requirements of `VectorRange`, then the return type will be `I`, where `I` is the index type of `T`. - -A call to `grb::shape` is expression-equivalent to: - -1) `t.shape()` if that expression is valid. -2) Otherwise, `shape(t)`, if that expression is valid, including any declarations of `shape` found through argument-dependent lookup. - -In all other cases, a call to `grb::shape` is ill-formed. - -## `grb::find` - -```cpp -template -inline constexpr /* unspecified */ find = /* unspecified */; -``` - -#### Call Signature -```cpp -template -requires /* see below */ -constexpr auto find(R&& r, T&& t); -``` - -Return an iterator to the stored value in the GraphBLAS matrix or vector `r` at index location `t`. - -A call to `grb::find` is expression-equivalent to: - -1) `r.find(t)` if that expression is valid. -2) Otherwise, any calls to `find(r, t)` found through argument-dependent lookup. -2) Otherwise, any calls to `std::find(r, t)`, if that expression is valid. - -In all other cases, a call to `grb::find` is ill-formed. - -## `grb::insert` - -```cpp -template -inline constexpr /* unspecified */ insert = /* unspecified */; -``` - -#### Call Signature -```cpp -template -requires /* see below */ -constexpr auto insert(R&& r, T&& t); -``` - -Attempt to insert the value `t` into the GraphBLAS matrix or vector `r`. - -A call to `grb::insert` is expression-equivalent to: - -1) `r.insert(t)` if that expression is valid. -2) Otherwise, any calls to `insert(r, t)` found through argument-dependent lookup. - -## `scalar_result_type_t` - -```cpp -template -using scalar_result_type_t = std::declval()( - std::declval>(), - std::declval>()); -``` - -The type of the scalar elements produced by combining GraphBLAS objects of type `A` and `B` elementwise using a binary operator of type `Combine`. - -## `multiply_result_t` - -```cpp -template -using multiply_result_t = /* undefined */; -``` - -The type returned when multiply is called on GraphBLAS matrix or vector ranges of type `A` and `B` using binary operators `Reduce` and `Combine` with mask `Mask`. - -The scalar type of the returned matrix will be `combine_result_t`, and the index type will be `grb::container_index_t
` or `grb::container_index_t`, whichever is able to store the larger value. - -## `combine_result_t` - -```cpp -template -using combine_result_t = std::invoke_result_t; -``` - -The type returned when the binary operator `Combine` is called with an element of the scalar type of `A` as the first argument and an element of the scalar type of `B` as the second argument. `A` and `B` must be GraphBLAS matrix or vector objects. - -## `ewise_union_result_t` - -```cpp -template -using ewise_union_result_t = /* undefined */; -``` - -The type returned when `ewise_union` is called on the GraphBLAS matrix or vector ranges of type `A` and `B` using the binary operator `Combine`. - -## `ewise_intersection_result_t` - -```cpp -template -using ewise_intersection_result_t = /* undefined */; -``` - -The type returned when `ewise_intersection` is called on the GraphBLAS matrix or vector ranges of type `A` and `B` using the binary operator `Combine`. \ No newline at end of file diff --git a/markdown/vector.md b/markdown/vector.md deleted file mode 100644 index aaf427a..0000000 --- a/markdown/vector.md +++ /dev/null @@ -1,330 +0,0 @@ -# `grb::vector` - -```cpp -template > -class grb::vector; -``` - -## Template Parameters -`T` - type of scalar values stored in the vector - -`I` - type, satisfying `std::integral`, used to store indices in the vector - -`Hint` - one or a composition of compile-time hints that may be used to affect the backend storage type - -`Allocator` - allocator type used to allocate memory - -## Member Types -Member Type | Definition ------ | ----- -`scalar_type` | `T`, the type of scalar elements stored in the vector -`index_type` | `I`, an integer type used to store vector indices -`key_type` | `index_type` -`map_type` | `scalar_type` -`value_type` | `grb::vector_entry`, a tuple-like type storing the indices and the stored element -`size_type` | A large unsigned integer type, usually `std::size_t` -`difference_type` | A large signed integer type, usually `std::ptrdiff_t` -`allocator_type` | `Allocator` -`iterator` | An iterator type fulfilling `std::forward_iterator` -`const_iterator` | A const iterator fulfilling `std::forward_iterator` -`reference` | `grb::vector_ref` -`const_reference` | `grb::vector_ref` -`scalar_reference` | Reference to `scalar_type` -`const_scalar_reference` | Const reference to `scalar_type` -`hint_type` | `Hint` - -## Methods -Method | Description ------ | ----- -`(constructor)` | Constructs vector -`size` | Number of stored elements in vector -`max_size` | Returns the maximum possible number of elements -`empty` | Return whether the vector is empty -`shape` | Return the dimension of the vector -`begin`
`cbegin` | Returns iterator to beginning of container -`end`
`cend` | Returns iterator to one past last element in container -`reshape` | Modify the dimension of the vector -`clear` | Clears all elements from the container -`insert` | Insert elements -`insert_or_assign` | Inserts or assigns elements -`find` | Finds an element -`operator[]` | Access or insert element - -## `grb::vector::vector` - -```cpp -vector(); (1) -vector(const Allocator& alloc); (2) -vector(index_type shape); (3) -vector(index_type shape, const Allocator& alloc); (4) -vector(const vector& other); (5) -vector(vector&& other); (6) -``` - -Constructs new `grb::vector` data structure. - -1) and 2) Constructs an empty vector of dimension 0. -3) and 4) Constructs an empty vector of dimension `shape`. -5) Copy constructor -6) Move constructor - -### Parameters -`shape` - shape of the vector to be constructed - -### Complexity -1) Constant -2) Implementation defined - -### Exceptions -May throw `std::bad_alloc`. - -## `grb::vector::size` -```cpp -size_type size() noexcept; -``` - -Returns the number of elements stored in the vector. - -### Parameters -(none) - -### Return value -Number of stored elements. - -### Complexity -Constant - -## `grb::vector::max_size` -```cpp -size_type max_size() noexcept; -``` - -Returns the maximum possible number of elements that could be stored in the vector due to platform or implementation limitations. - -### Parameters -(none) - -### Return value -Maximum possible number of elements. - -### Complexity -Constant - -## `grb::vector::empty` -```cpp -bool empty() noexcept; -``` - -Returns whether the vector is empty, that is where `size() == 0`. - -### Parameters -(none) - -### Return value -Whether the vector is empty. - -### Complexity -Constant - -## `grb::vector::shape` -```cpp -index_type shape() const noexcept; -``` - -Returns the dimension of the vector. - -### Parameters -(none) - -### Return value -Dimension of the vector. - -### Complexity -Constant - -## `grb::vector::begin` and `grb::vector::cbegin` -```cpp -iterator begin() noexcept; -const_iterator begin() const noexcept; -const_iterator cbegin() const noexcept; -``` - -Returns an iterator to the first element of the vector data structure. If the vector is empty, returns an element that compares as equal to `end()`. - -### Parameters -(none) - -### Return value -Iterator to the first element - -### Complexity -Constant - -## `grb::vector::end` and `grb::vector::cend` -```cpp -iterator end() noexcept; -const_iterator end() const noexcept; -const_iterator cend() const noexcept; -``` - -Returns an iterator to one past the last element of the vector data structure. This element is used only to signify the end of the container, and accessing it has undefined behavior. - -### Parameters -(none) - -### Return value -Iterator to one past the last element. - -### Complexity -Constant - -## `grb::vector::reshape` -```cpp -void reshape(index_type shape); -``` - -Reshape the vector. That is, modify the vector dimension such that vector is now of dimension `shape`. -If any nonzeros lie outside of the new vector shape, they are removed from the vector. - -### Parameters -`shape` - New vector shape - -### Return value -None - -### Complexity -Implementation defined - -## `grb::vector::clear` -```cpp -void clear(); -``` - -Clear all stored scalar values from the vector. The vector maintains the same shape, but after return will now have a size of 0. - -### Complexity -Implementation defined - -## `grb::vector::insert` -```cpp -template -void insert(InputIt first, InputIt last); (1) -std::pair insert(const value_type& value); (2) -std::pair insert(value_type&& value); (3) -``` - -Inserts an element or number of elements into the vector, if the vector doesn't already contain a stored element at the corresponding index. - -(1) Insert elements in the range `[first, last)` if an element does not already exist in the vector at the corresponding index. If multiple elements in `[first, last)` have the same indices, it is undefined which element is inserted. - -(2) and (3) Insert the element `value` if an element does not already exist at the corresponding index in the vector. - -### Parameters -`first`, `last` - Range of elements to insert - -`value` - element to insert - -### Return value -(1) None - -(2) and (3) return a `std::pair` containing an `iterator` and a `bool` value. The `bool` value indicates whether or not the insertion was successful. If the insertion was successful, the first value contains an iterator to the newly inserted element. If it was unsuccessful, it contains an iterator to the element that prevented insertion. - -### Complexity -Implementation defined - -## `grb::vector::insert_or_assign` -```cpp -template -std::pair insert_or_assign(key_type k, M&& obj); -``` - -Inserts an element into index `k` in the vector and assigns to the scalar value if one already exists. - -If an element already exists at index location `k`, assigns `std::forward(obj)` to the scalar value stored at that index. If no element exists, inserts `obj` at the index as if by calling `insert` with `value_type(k, std::forward(obj))`. - -### Parameters -`k` - the index location to assign `obj` - -`obj` - the scalar value to be assigned - -### Type Requirements -`M` must fulfill `std::is_assignable` - -### Return Value -Returns an `std::pair` with the first element holding an iterator to the newly inserted or assigned value and the second element holding a `bool` value that is `true` if the element was inserted and `false` otherwise. - -### Complexity -Implementation defined. - -## `grb::vector::erase` -```cpp -size_type erase(index_type index); -``` - -Erases the element stored at index `index` if one exists. - -### Parameters -`index` - the index of the scalar value to erase - -### Return Value -Returns the number of elements erased (0 or 1). - -### Complexity -Implementation defined. - -## `grb::vector::find` -```cpp -iterator find(index_type index); -const_iterator find(index_type index) const; -``` - -Finds the element at location `index` in the vector, returning an iterator to the element. If no element is present at the location, returns `end()`. - -### Parameters -`index` - Location of the vector element to find - -### Return value -An iterator pointing to the vector element at the corresponding index, or `end()` if there is no element at the location. - -### Complexity -Implementation defined - -## `grb::vector::operator[]` -```cpp -scalar_reference operator[](index_type index); -const_scalar_reference operator[](index_type index) const; -``` - -Returns a reference to the scalar value stored at location `index` in the vector. If no value is stored at the location, inserts a default constructed value at the location and returns a reference to it. - -### Parameters -`index` - Location of the vector element - -### Return value -A reference to the scalar value at location `index`. - -### Complexity -Implementation defined - -## `grb::vector::at` -```cpp -scalar_reference at(index_type index); -const_scalar_reference at(index_type index) const; -``` - -Returns a reference to the scalar value stored at location `index` in the vector. If no value is stored at the location, throws the exception `grb::out_of_range`. - -### Parameters -`index` - Location of the vector element - -### Return value -A reference to the scalar value at location `index`. - -### Complexity -Implementation defined - -### Exceptions -If no element exists at location `index`, throws the exception `grb::out_of_range`. diff --git a/markdown/views.md b/markdown/views.md deleted file mode 100644 index d6de2bc..0000000 --- a/markdown/views.md +++ /dev/null @@ -1,262 +0,0 @@ -# Views - -## grb::views::transpose - -```cpp -namespace views { - inline constexpr /* unspecified */ transpose = /* unspecified */; -} -``` - -##### Call signature - -```cpp -template -MatrixRange auto transpose(M&& matrix); -``` - -### Parameters - -`matrix` - a GraphBLAS matrix or matrix view - -#### Type Requirements - -- `M` must meet the requirements of `MatrixRange` - -### Return Value -Returns a matrix view that is equal to the transpose of `matrix`, satisfying `MatrixRange`. - -If the value returned by `transpose` outlives the lifetime of `matrix`, then the behavior is undefined. - -## grb::views::transform - -```cpp -namespace views { - inline constexpr /* unspecified */ transform = /* unspecified */; -} -``` - -##### Call signature -```cpp -template -MatrixRange auto transform (M&& matrix, Fn&& fn); (1) - -template -VectorRange auto transform(V&& vector, Fn&& fn); (2) -``` - -(1) `fn` must accept an argument of type `std::ranges::range_value_t` and return a value of some type. The return type of `fn` will be the scalar type of the transform view. - -(2) `fn` must accept an argument of type `std::ranges::range_value_t` and return a value of some type. The return type of `fn` will be the scalar type of the transform view. - -### Parameters - -`matrix` - a GraphBLAS matrix or matrix view satisfying `MatrixRange` - -`vector` - a GraphBLAS vector or vector view satisfying `VectorRange` - -`fn` - function used to transform matrix values element-wise - -#### Type Requirements - -- `M` must meet the requirements of `MatrixRange` - -- `V` must meet the requirements of `VectorRange` - -### Return Value - -(1) Returns a view of `matrix` satisfying `MatrixRange`. The stored scalar values will correspond to every stored scalar value in `matrix` transformed using the function `fn`. - -(2) Returns a view of `vector` satisfying `VectorRange`. The stored scalar values will correspond to every stored scalar value in `vector` transformed using the function `fn`. - -### Example - -```cpp -#include - -int main(int argc, char** argv) { - grb::matrix a({10, 10}); - - a[{1, 2}] = 12.0f; - a[{3, 4}] = 123.2f; - a[{7, 8}] = 8.0f;; - - grb::print(a, "original matrix"); - - // Transform each scalar value based on its - // row and column index. - auto idx_view = grb::views::transform(a, [](auto&& entry) { - auto&& [idx, v] = entry; - auto&& [i, j] = idx; - return i + j; - }); - - grb::print(idx_view, "index transformed view"); - - return 0; -} -``` - -## grb::structure -```cpp -template -grb::structure_view structure(M&& matrix); (1) - -template -grb::structure_view structure(V&& vector); (2) -``` - -### Parameters - -`matrix` - a GraphBLAS matrix or matrix view - -`vector` - a GraphBLAS vector or vector view - -#### Type Requirements - -- `matrix` must meet the requirements of `MatrixRange` - -- `vector` must meet the requirements of `VectorRange` - -### Return Value - -(1) Returns a view of the matrix - -#### Possible Implementation - -```cpp -inline constexpr bool always_true = [](auto&&) { return true; }; - -template -using structure_view = grb::transform_view; - -template -grb::structure_view structure(M&& matrix) { - return grb::transform(std::forward(matrix), always_true); -} - -template -grb::structure_view structure(V&& vector) { - return grb::transform(std::forward(vector), always_true); -} -``` - -## grb::filter - -```cpp -template -grb::filter_view filter(M&& matrix, Fn&& fn); (1) - -template -grb::filter_view filter(V&& vector, Fn&& fn); (2) -``` - -### Parameters - -`matrix` - a GraphBLAS matrix - -`vector` - a GraphBLAS vector - -`fn` - a function determining which elements should be filtered out - -#### Type Requirements - -- `M` must meet the requirements of `MaskMatrixRange` - -- `V` must meet the requirements of `MaskVectorRange` - -- `fn` must accept an argument of type `std::ranges::value_type_t` (1) or `std::ranges::value_type_t` (2) and return a value of type `bool`. - -### Return Value - -Returns a filtered view of the matrix `matrix` or vector `vector`. The return value fulfills the requirements of `MatrixRange` (1) or `VectorRange` (2) . The return value has the same shape as the input object, but without elements for which `fn(e)` evaluates to false. - -## grb::complement - -```cpp -template -grb::complement_view complement(M&& mask); (1) - -template -grb::complement_view complement(V&& mask); (2) -``` - -### Parameters - -`mask` - a GraphBLAS mask - -#### Type Requirements - -- `M` must meet the requirements of `MaskMatrixRange` - -- `V` must meet the requirements of `MaskVectorRange` - -### Return Value - -_TODO: Scott, Jose, is this the behavior we want?_ -Returns the complement view of a matrix or vector mask. At every index in `mask` with no stored value or with a scalar value equal to `false` when converted to `bool`, the returned view has a stored value with the scalar value `true`. At every stored value in `mask` with a scalar value equal to `true` when converted to `bool`, the return view has no stored value. - -(1) Returns a matrix view satisfying the requirements `MaskMatrixRange`. - -(2) Returns a vector view satisfying the requirements `MaskVectorRange`. - - -## grb::mask - -```cpp -template -grb::masked_view mask(Matrix&& matrix, M&& mask); (1) - -template -grb::masked_view mask(Vector&& vector, M&& mask); (2) -``` - -### Parameters - -`matrix` - a GraphBLAS matrix or vector - -`mask` - a GraphBLAS mask with the same shape as `matrix` (1) or `vector` (2) - -#### Type Requirements - -- `Matrix` must meet the requirements of `MatrixRange` - -- `Vector` must meet the requirements of `VectorRange` - -- `M` must meet the requirements of `MaskMatrixRange` (1) or `MaskVectorRange` (2) - -### Return Value - -Returns a view of the matrix `matrix` (1) or vector `vector` that has been masked using `mask`. Any value in `matrix` for which `mask` does not have an entry at the corresponding location or for which `mask` has a value equal to `false` when converted to `bool` will not be visible in the returned mask view. - -(1) Returns a matrix view satisfying the requirements `MatrixRange`. Any values in `matrix` for which `grb::find(mask, index) == grb::end(mask) || bool(*grb::find(mask, index)) == false` will be masked out of the returned matrix view. - -### Exceptions - -The exception `grb::invalid_argument` is thrown if the `mask` does not have the same shape as `matrix` (1) or `vector` (2). - -## grb::submatrix_view -```cpp -template -grb::submatrix_view submatrix(M&& matrix, grb::index rows, grb::index cols); -``` - -#### Parameters - -`matrix` - a GraphBLAS matrix - -`rows` - the span of rows in the submatrix view - -`cols` - the span of columns in the submatrix view - -### Return Value - -Returns a view of the submatrix of GraphBLAS matrix `matrix` formed by the intersection of rows `rows[0]` to `rows[1]` and columns `cols[0]` to `cols[1]`. -The returned matrix range has shape `grb::min(rows[1], grb::shape(matrix)[0]) - grb::max(rows[0], 0)` by `grb::min(cols[1], grb::shape(matrix)[1]) - grb::max(cols[0], 0)` -and contains all stored values for whose index the expression `index[0] >= rows[0] && index[0] < rows[1] && index[1] >= cols[0] && index[1] < cols[1]` holds true. - -### Exceptions -Returns the exception `grb::invalid_argument` if `rows[0] > rows[1]` or `cols[0] > cols[1]`. - - - diff --git a/minutes/assets/2022-05-10-120147_1256x859_scrot.png b/minutes/assets/2022-05-10-120147_1256x859_scrot.png deleted file mode 100644 index 8d3c4dd..0000000 Binary files a/minutes/assets/2022-05-10-120147_1256x859_scrot.png and /dev/null differ diff --git a/minutes/assets/2022-05-10-120718_878x495_scrot.png b/minutes/assets/2022-05-10-120718_878x495_scrot.png deleted file mode 100644 index 8e91564..0000000 Binary files a/minutes/assets/2022-05-10-120718_878x495_scrot.png and /dev/null differ diff --git a/minutes/assets/2022-05-24-121445_1358x652_scrot.png b/minutes/assets/2022-05-24-121445_1358x652_scrot.png deleted file mode 100644 index 117c7fb..0000000 Binary files a/minutes/assets/2022-05-24-121445_1358x652_scrot.png and /dev/null differ diff --git a/minutes/minutes-2022-05-31.md b/minutes/minutes-2022-05-31.md deleted file mode 100644 index fd6bed8..0000000 --- a/minutes/minutes-2022-05-31.md +++ /dev/null @@ -1,77 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - May 31, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda -Discuss the idea of a SparseBLAS that is different from GraphBLAS shown in following code presented by Jose: - -``` -namespace spb -/* - * This is the SparseBLAS part of GraphBLAS. - */ -{ - template class BinaryOp - { - virtual T operator()(const T&, const T&) = 0; - }; - - template class ArithmeticPlus : public BinaryOp - { - T operator()(const T& x, const T& y) { return x+y; } - }; - - template class ArithmeticTimes : public BinaryOp - { - T operator()(const T& x, const T& y) { return x*y; } - }; - - template class Matrix - { - }; -} - -spb::ArithmeticPlus plus_F64; -spb::ArithmeticTimes times_F64; - -namespace srb -/* - * This is the SemiringBLAS part of GraphBLAS. - */ -{ - template class Semiring - { - public: - /* - * Constructs a semiring over domain T with the specified addition and multiplication operations. - * If the two operations do not form a semiring over T, the result is undefined. - */ - Semiring(const spb::BinaryOp& addition, const spb::BinaryOp& multiplication); - - spb::Matrix mxm(spb::Matrix&, spb::Matrix&); - spb::Matrix eWiseAdd(spb::Matrix&, spb::Matrix&); - spb::Matrix eWiseMult(spb::Matrix&, spb::Matrix&); - }; -} - -srb::Semiring plus_times_F64(plus_F64, times_F64); -``` - -## Minutes - -Jose's main points are as follows: - -1. This is not an API proposal. It is intended to illustrate my thinking. I am not well versed in modern C++ and this is an "old-fashioned" example. -2. One of the components of GraphBLAS is the "Semiring BLAS". This is in addition to a more basic "Sparse BLAS" that defines containers like matrices and vectors, and basic algebraic objects such as binary operations. -3. In the attached file, the basic "Sparse BLAS" corresponds to namespace "spb". The "Semiring BLAS" corresponds to namespace "srb". This is more for referring to the two components. I am not suggesting that they should be separate name spaces in the actual API. -4. Semirings are constructed from a domain and two binary operations. If the binary operations do not form a semiring in the specified domain, the result of the constructor is undefined. (And, as a consequence, any use of the resulting object is undefined.) -5. Matrix multiply (mxm), element-wise addition (eWiseAdd) and element-wise multiplication (eWiseMult) are methods of a semiring object. Their results will be well defined if the semiring is defined. Undefined otherwise. -6. In my ideal scenario, only methods from the Semiring BLAS can have undefined behavior. All methods from Sparse BLAS would always produce defined results. The requirements for those methods should be enforced by syntax only. (For example, there should not be a requirement for a binary operation to be commutative. Leave that for the Semiring BLAS.) -7. Yes, maybe we need a "Monoid BLAS" too, but we can have a lot of discussion without that :-) -Finally, here is a pragmatic recommendation for us to make progress: I think we should move ahead with defining the API without an explicit Semiring type. (I think this is Scott's view, but I should let him confirm.) Let us see where that take us. We can then evaluate what we got and decide if there would be be benefit from semiring classes. - diff --git a/minutes/minutes-2022-06-07.md b/minutes/minutes-2022-06-07.md deleted file mode 100644 index 4842f1f..0000000 --- a/minutes/minutes-2022-06-07.md +++ /dev/null @@ -1,54 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - June 7, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda -Scott spent the bulk of the meeting explaining my thoughts surrounding the Semiring concept in the context of mxm. - - -## Minutes - -I spent the bulk of the meeting explaining my thoughts surrounding the Semiring concept in the context of mxm (because it does not make sense to me to discuss the issue of semiring anywhere except in the context of matrix multiplication…sorry I have a mental block otherwise). At some point Jose asked a really good question: “If I use this interface will the result be deterministic?” and I don’t know how to get at the answer at the moment but I think we should consider the following to work through it (paper being presented at ECOOP 2022 this month): - -The first (and major) phase of the generic programming process is sometimes known as “lifting” where we create generic algorithms through a process of successive generalization. -That is, the process is -1. Study the concrete implementation of an algorithm; (We already have some) -2. Lift away unnecessary requirements to produce a more abstract algorithm; (I am in this process now) -3. Repeat the lifting process until we have obtained a generic algorithm that is as general as possible but that still instantiates to efficient concrete implementations; and -4. Catalog remaining requirements and organize them into concepts. - -Once the algorithm (like mxm) is lifted and made appropriately generic it is specialized (the dual of lifting) through composition of concrete types to realize a concrete implementation. A single algorithm can be specialized in many different ways depending on the concrete types and I believe it is our job to allow for the widest range of valid implementations. But we still need to decide what the valid implementations are and this is related to what Jose was trying to address last week…I think that one mxm (or multiply) function signature can cover the two philosophies. - -I need to start at the last slide I showed. - -``` -template , //All three types the same? - BinaryOp CombineType = std::multiplies<>, - MaskMatrixView MaskType = grb::full_mask<> - > //requires the types relationship??? -auto multiply(AMatrixType &&a, - BMatrixType &&b, - ReduceType &&reduce = ReduceType(), - CombineType &&combine = CombineType(), - MaskType &&mask = MaskType()); // or grb::full_mask()); -``` - -I believe the question we should be asking: what is the minimum required by mxm (or multiply). - -- Since it is computing a sparse result we don’t strictly need to know what the reducer’s identity is - - But if there was an identity then an implementation could use a different implementation (could be useful for multithreaded or distributed or Joe Eaton implementations) -- What if we knew the reducer’s annihilator? - - The implementation could potentially short circuit the reduction and exit early -- What if we knew the reducer is associative - - The implementation could more than just in-order reductions and be able to implement others that use divide and conquer -- What if we knew the reducer is commutative - - The implementation would be free to reorder and distribute the computation in any way it wants (e.g. cyclic distributions). - -Getting back to Jose’s question, what is actually required to ensure implementations are deterministic. Is it that the input types and the output type of the reducer need to be all one type? diff --git a/minutes/minutes-2022-06-14.md b/minutes/minutes-2022-06-14.md deleted file mode 100644 index 3452985..0000000 --- a/minutes/minutes-2022-06-14.md +++ /dev/null @@ -1,50 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - June 14, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [ ] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -Continue discussion of mxm. - - -## Minutes - -First, an interesting presentation at PLDI/ARRAY this week on mdspan unfortunately there was a problem with the recording so only the slides are available (perhaps will influence future work on hierarchical iterators for matrices): https://pldi22.sigplan.org/details?action-call-with-get-request-type=1&7c8254b9cac74799882acdf9d254f333action_174265066103ebc69eab63bbac9cb4a92cb0fd36ba4=1&__ajax_runtime_request__=1&context=pldi-2022&track=ARRAY-2022-papers&urlKey=8&decoTitle=Multidimensional-C - -This week it was just Jose and I trying to answer the questions posed in the previous week (minutes below). Assuming we don’t have a Semiring concept(still TBD), we focused on the type requirements (concepts) for the reduce and combine operators in the mxm operation. - -Regarding the “deterministic” question: -- There are times we want random numbers (i.e. non-deterministic)…like in MIS and Louvain to break ties or perhaps in some future random walk like operation -- Maybe the answer/language is: “If the operators are deterministic then the operations should be deterministic” - -Regarding the mxm operators. The first and easier one is the combine operator: -- It does not need to be commutative nor associative -- It can be three types T1 x T2 --> T3 (whether those types are deduced by the compiler or explicitly specified by the user) -- Casting will occur as needed and supported by the language -- Note: if a particular cast is not supported the code will not compile -- I believe these are the basic requirements of BinaryOp concept - -The reduce conversation lasted longer -- QUESTION #1: Must the reducer in mxm be all of one type; i.e. T x T --> T (we think so) -- QUESTION #2: Must the reducer in mxm be of the output type produced by the combiner? (not as sure) -- If only the we don’t have a semiring object (thus mxm is written as below), then - - #2 would imply there must be a requirement on the mxm operation itself that ties the type of the reducer to the output type produced by the combiner. Or maybe it is a weaker “convertible to” requirement - - #1 could be a requirement on mxm or captured by a new Concept (UniTypeBinaryOp?) -- QUESTION #3: Should the reducer be associative and commutative? - - Cutting to the chase: The math is currently defined on line 2953 of the C API - - In short, if the intersection set is unordered, then we believe that both associativity and commutativity are required - - We cannot check these mathematical properties so these alone can’t be part of concept checking - - What is clear is that we don’t require an identity to implement this, but if identity is - - There is a hierarchy of concepts forming - - BinaryOp - - UniTypeBinaryOp (restricts the types of the operands and output) and assumes commutativity and associativity - - CommutativeMonoid (adds the existence of identity) and assume commutativity and associativity - - If commutativity/associativity are required, then are the results undefined(?) if the operator does not satisfy that? - - - If commutativity/associativity ARE NOT required, then we will need to revisit the mathematical descriptions of the operations - diff --git a/minutes/minutes-2022-06-21.md b/minutes/minutes-2022-06-21.md deleted file mode 100644 index a601462..0000000 --- a/minutes/minutes-2022-06-21.md +++ /dev/null @@ -1,66 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - June 21, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [ ] Jose Moreira - -## Agenda - -The conversation centered mainly around Question #3 from last week (below) about the requirements on reducers in mxm, mxv, vxm and reduce operations. Scott believes these are different from “addition” binary ops that show up in accumulate and ewise_add. - -## Minutes - -We ended the conversation with something similar to the following: - -DESIGN GOAL: find the right balance between maximizing the user’s “useful” flexibility while minimizing the burden on the library developer - -Operator properties (traits) are in play (are there other useful ones?): -- Unityped: A binary operator on one domain (a Magma?) -- Associativity: sans commutativity when more than two operands exist consecutive pairs can be arbitrarily grouped as long as order maintained -- Commutativity: means any pair of operands can be operated on in any order. The set must be in one Domain and the operator inputs must be one type. - - Note commutativity does not imply associativity. I don’t know if the algebra’s are relevant in GraphBLAS -- Identity: If it has a known identity then operator will behave as if the unstored element is of that type. -- Annihilator: If it has a known annihilator if partial reduction achieves this value the reduction can be short circuited. -- Idempotence: doubt this is generally useful…maybe a niche case in logical AND and OR. T^T=T, F^F=F - -The BinaryOp concept -- Does not promise any of the properties/traits -- I believe can be used in element-wise addition and accumulation, AND element wise multiplication and the multiply portion of matrix multiplication -- however an implementation is free to check for any of the properties/traits but not sure it would reasonably need to have implementation variants - -Reducer concept: -- Needs to be UniType -- Spec could reasonable require Associativity (without checking for the trait?) - - This allows the additions to be done out of order but the operands must stay in order. - - E.g., cyclic distribution is problematic without this - - Subtraction, division, exponentiation are not associative -- Commutativity should be encouraged (but should it be required) - - This allows for arbitrary distribution and order of operation on data -- Identity is not necessary - - This should be optional and encouraged, - - Could lead to more performant implementations especially parallel/distributed codes -- Annihilator is not necessary - - This must be optional - - Could lead to more performant implementations in key benchmarks (i.e. BFS) - -Monoid Concept is associative and has an identity (should satisfy BinaryOp and Reducer) - -Commutative Monoid Concept is associative, commutative, and has an identity (should satisfy BinaryOp and Reducer) - - -Casting notes: -- accumulator BinaryOp (generally): C x T -> Z, or (T1)C x (T2)T -> Z -- mxm C += AB (and mxv, vxm) - - multiply BinaryOp: A x B -> T or (T1)A x (T2)B -> T3 - - add Reducer UniTypeBinaryOp: (T)T3 x (T)T3 -> T (possible casting) - - Does not really have a type constraint with the output of the multiply (each product could be cast once to T4 and a deterministic reduction is carried out in T - - Accum BinaryOp: C x T -> Z, or (T1)C x (T2)T -> Z - - mask: Z -> C -- reduce C = +(A) - - add Reducer UniTypeBinaryOp: A x A -> T (possible casting): (T)A x (T)A -> T - - Accum BinaryOp: C x T -> Z, or (T1)C x (T2)T -> Z - - mask: Z -> C -- etc diff --git a/minutes/minutes-2022-06-28.md b/minutes/minutes-2022-06-28.md deleted file mode 100644 index d7fe72b..0000000 --- a/minutes/minutes-2022-06-28.md +++ /dev/null @@ -1,66 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - June 28, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -Today, we limited our conversation to what should be required of a reducer in the context of mxm (but it also applies to mxv, vxm, and reduce). - -Here is the API being discussed for reference: - -``` -template , //All three types the same? - BinaryOp CombineType = std::multiplies<>, - MaskMatrixView MaskType = grb::full_mask<> - > //requires the types relationship??? -auto multiply(AMatrixType &&a, - BMatrixType &&b, - ReduceType &&reduce = ReduceType(), - CombineType &&combine = CombineType(), - MaskType &&mask = MaskType()); // or grb::full_mask()); -``` - -## Minutes - -We were are discussing the requirements with respect to the “elemental” (atomic?) mathematical properties: associativity, commutativity, identity, annihilator,… - -We only discussed whether or not we should require associativity: -- We all agreed that deterministic reduction can be implemented without associtativity. Tim asserts (and Scott believes) that this forces a purely sequential implementation (i.e., parallelism requires associativity). -- The question then becomes what is the burden on implementors if the API requires support for non-associative reducers? - - Scott believes the burden is greatest on distributed implementors and perhaps GPU implementation. Meaning these groups are least likely to even want to consider a sequential implementation. - -We discuss how associativity might be implemented/checked: -- An associativity type trait could be implemented and all known built-in operators could be defined as associative, and implementations could ask about it - - Exception: We would want to say that floating point operations are associative (even though they aren’t) -- What happens if mxm requires associativity and the operator is not? - - We could perform a compile time check of the trait and not compile -- What happens if mxm does not require associativity - 1. All implementations would have to implement a strictly sequential version - 2. OR allow the COP-OUT clause: implementors could choose to not implement the non-associative version. The behaviour could be implemented two different ways - a. Compile time: the implementors mxm requires associativity and does not compile otherwise. - b. Run time: the implementor uses the trait to implement two different functions and the non-associative one throws a NOT_IMPLEMENTED exception -- The associativity trait could be defined for user-defined operators, what happens if the user does this for a non-associative function? - - Undefined behaviour could result. - - Jose asks is this bounded undefined behaviour or not - - -The COP-OUT clause (number 2 above) is where the conversation was starting to converge to. But this is a foundational API design philosophy that we need a unanimous decision on how we will proceed. - - -Aside for later: Jose mentioned that specifying undefined behaviour can be tricky. We will need to revisit these terms: -- Syntax guaranteed -- Undefined -- Bounded undefined - -Aydin sent the following statement: - -But regarding non-associativity; it is hard but not completely impossible afaik: https://project-archive.inf.ed.ac.uk/msc/20172484/msc_proj.pdf - -In this document, we have presented an algorithm for the derivation of a tree-parallel implementation to sequential reductions with non-associative operators, with an associated implementation for the Lift compiler. In addition to the transformation, we have designed a series of addition to Lift to integrate the transformation with the rest of the language better, and we have provided implementations for some of these additions. Moreover, through a series of comparisons with unoptimised Lift code and equivalent handwritten implementations for other platforms, we have established the usefulness of the approach diff --git a/minutes/minutes-2022-07-05.md b/minutes/minutes-2022-07-05.md deleted file mode 100644 index d4326de..0000000 --- a/minutes/minutes-2022-07-05.md +++ /dev/null @@ -1,115 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - July 5, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [X] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -Discuss Jose's proposal of using code as specification - -Here is the API being discussed for reference: - -``` -template -auto multiply(AMatrixType &&a, - BMatrixType &&b, - BinaryOpType &&reduce, - BinaryOpType &&combine); -``` - -An implementation must produce the same result as produced by an execution of the following reference implementation: - -``` -template -auto multiply(AMatrixType &&a, - BMatrixType &&b, - BinaryOpType &&reduce, - BinaryOpType &&combine) -{ - Matrix c; - - for (auto&& [a_index, a_value] : a) - { - auto&& [i,k] = a_index; - for (auto&& [b_index, b_value] : b.row(k)) - { - auto&& [k,j] = b_index; - if (c.contains(i,j)) c(i,j) = reduce(c(i,j), combine(a_value, b_value)); - else c(i,j) = combine(a_value, b_value); - } - } - - return c; -} -``` - -Note 1: An implementation may require that the reduce binary operator be associative and/or commutative. In that case, the implementation must clearly state that requirement. A program that violates that requirement is considered noncompliant for that implementation. - -Note 2: An implementation may assume floating-point arithmetic to have the properties of real number arithmetic. In that case, the implementation must clearly state that assumption and list the floating-point formats for which it is assumed. - - -## Minutes - -- Jose said that code should be used to specify the behaviour of the operations instead of the math that is found in the current API specification. -- Furthermore the 1D unordered iterators presented in our GrAPL paper should be used to define that behaviour (this is shown in the code for C=AB below). -- A key point of the proposal is that “an execution” (meaning any) of the code is a valid result - - Scott pointed out that if the order of the for loops is not defined, AND if the reduction operator is not commutative and associative then many different possible values would then be deemed valid - - If the operator is not commutative and the order that products are reduce is indeterminate, then the results can vary with each execution - - Further, If the operator is not associative, then different divisions of divide-and-conquer will produce different results. -- Tim and Scott did not think this was the correct approach - - Response #1: we require commutativity and associativity of reducer and use this code as the spec (but Scott wants to allow less restrictions) - - Response #2: we should impose more requirements to the iteration order in order to allow more options (but Tim does not what a spec in terms of code, and Scott says there is a lot of work involved in (i) specifying more types of iteration, and (ii) implementing more types of iteration, and there is upcoming work on multi-dimensional iteration in the C++ ISO community that could be leveraged in a later version of the spec - - Response #3: the spec should be in terms of the math, and the spec should have to be in terms of the 1D iterator we are proposing. - -- Scott’s response: - - This issue is about what order elements in the nested for-loops are visited: - ``` - for (auto&& [a_index, a_value] : a) - for (auto&& [b_index, b_value] : b.row(k)) - ``` - - These two loops basically define the order in which the elements of the intersection sets described by the summation math get processed on line 2953 of the C API Specification V2.0.0 - - Note: If the intersection set of the math is unordered then this math also requires that the reducer op be associative and commutative (which is what the C API required). - - Scott’s proposal is to keep this math (instead of Jose’s code)..but add a few extra requirements on the intersection set. For example: - - If \oplus is commutative and associative there is no order imposed on the summation - - If \oplus is non-commutative and non-associative, the intersection set must be processed sequential in order of increasing k - - If \oplus is non-commutative and associative, the relative order is still increasing but blocks of contiguous elements can be processed in parallel and the partial results must be reduced in the correct order - - Etc - - If \oplus has a defined annihilator then any time the current partial reduction computes to the annihilator value, the reduction can be short circuited - - Etc (again) - - Scott’s opinion: By specifying the math instead of code, we get the following benefits: - - we put more restrictions on what is considered a valid execution that is more in line with what math requires - - we sidestep the issue of requiring specific code constructs (like ordered iteration, or hierarchical iteration) that Ben and Scott feel are beyond the scope of the v1.0 API, and perhaps a bit premature given that the C++ ISO committee are debating similar issues that could be leveraged with a later adoption by the GraphBLAS spec. - - - -## Conversation after the meeting - -Tim Mattson wrote an email pushing for using math as spec as was done in the C API. - -Jose's position: - -I realize that my proposal is radically different from the way we did things with the C API. And that is why it deserves some investigation. - -Let us consider some of the advantages of “spec as code”, particularly as specified in the example below: -1. Two for the price of one. We will get both the spec and a reference implementation for the same amount of work. -2. The spec can be tested. It is just code. When we test the reference implementation, we are testing the spec. -3. The resulting spec will be much more concise. Compare the code below with the pages of text in the C API. -4. It is less work for us. We will finish it quickly. Likely in time for SC22. -5. Even foundational constructs such as the unordered iterators can be defined through code. (The iterator for an STL unordered set is also unordered.) -6. Code is concrete. We can talk about line numbers and variable names and for loops. We know it is right when it works. -7. If code is not clear we can always … improve it until it is. (You didn’t think I was going to say “add comments”, did you?) -8. There are no API errors to define. If it compiles, it runs. -9. We can even eliminate most execution errors. I suspect only “OUT_OF_MEMORY” and “PANIC” are truly necessary. - diff --git a/minutes/minutes-2022-07-12.md b/minutes/minutes-2022-07-12.md deleted file mode 100644 index 3356c20..0000000 --- a/minutes/minutes-2022-07-12.md +++ /dev/null @@ -1,130 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - July 12, 2022 - -## Attendees -- [ ] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [X] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -Continued to discuss Jose's proposal of using code as specification - -Let us consider some of the advantages of “spec as code”, particularly as specified in the example below: -1. Two for the price of one. We will get both the spec and a reference implementation for the same amount of work. -2. The spec can be tested. It is just code. When we test the reference implementation, we are testing the spec. -3. The resulting spec will be much more concise. Compare the code below with the pages of text in the C API. -4. It is less work for us. We will finish it quickly. Likely in time for SC22. -5. Even foundational constructs such as the unordered iterators can be defined through code. (The iterator for an STL unordered set is also unordered.) -6. Code is concrete. We can talk about line numbers and variable names and for loops. We know it is right when it works. -7. If code is not clear we can always … improve it until it is. (You didn’t think I was going to say “add comments”, did you?) -8. There are no API errors to define. If it compiles, it runs. -9. We can even eliminate most execution errors. I suspect only “OUT_OF_MEMORY” and “PANIC” are truly necessary. - - -Here is the API being discussed for reference: - -``` -template -auto multiply(AMatrixType &&a, - BMatrixType &&b, - BinaryOpType &&reduce, - BinaryOpType &&combine); -``` - -An implementation must produce the same result as produced by an execution of the following reference implementation: - -``` -template -auto multiply(AMatrixType &&a, - BMatrixType &&b, - BinaryOpType &&reduce, - BinaryOpType &&combine) -{ - Matrix c; - - for (auto&& [a_index, a_value] : a) - { - auto&& [i,k] = a_index; - for (auto&& [b_index, b_value] : b.row(k)) - { - auto&& [k,j] = b_index; - if (c.contains(i,j)) c(i,j) = reduce(c(i,j), combine(a_value, b_value)); - else c(i,j) = combine(a_value, b_value); - } - } - - return c; -} -``` - -Note 1: An implementation may require that the reduce binary operator be associative and/or commutative. In that case, the implementation must clearly state that requirement. A program that violates that requirement is considered noncompliant for that implementation. - -Note 2: An implementation may assume floating-point arithmetic to have the properties of real number arithmetic. In that case, the implementation must clearly state that assumption and list the floating-point formats for which it is assumed. - -## Minutes - -- We discussed Jose’s proposal about code as spec (abov). - - Scott voiced concerns again about depending on a public API that may not exist v1.0 and is not sure should exist right now given that the data structures are opaque. Ben and Scott specifically punted on things like ordered iterators for a number of reasons including the burden it would place on library writers to do it efficiently (they wanted to spend more time thinking about the implications). - - But maybe the point is that a lower level public API on matrices and vectors needs to be expanded to support what Jose is suggesting. - - Tim supports basing the API spec on math requirements - - Jose asserts that the code approach is less work. - - Scott is not sure that code reqs are less work depending on how much new API is required and whether or not we have spec language for the complexities. For example, the code snippet also requires methods like a row accessor (“row(k)”) on matrices which possibly implies a partial ordering (maybe not if you just accept that row(k) is a view of the basic iterator and iterating over a row is O(m) complexity. -- Scott’s initial purpose for examining the reducer in mxm was to try to firmly establish what would be required of that operator. - - The majority consensus seems to be that we should require commutativity and associativity because: - - That is what the C API required - - It would be less work and we have an SC22 deadline - - Scott points out that we can always make the operator less restrictive in the future without breaking backward compatibility - - It still begs the question of whether or not we will require an identity value even though is would not be used in the code req’s -- We ended the meeting with two Action Items: - - Jose will expand the code example below to include optional accumulation and masking. - - Scott suggested taking the approach that the sequential implementation of GBTL took and make it explicitly a 3 step process with T and Z intermediate matrices. - - Scott and Tim need to estimate and rough draft what a separate math spec would look like. - - The consensus opinion was that both spec committees (C and C++ and maybe other languages) should build their language API specs on this new math document - - Scott thinks that extracting the optional accumulation and masking steps into their own sections could significantly reduce the size of the spec. - -## Conversation about error codes after the meeting - -We did not get a chance to discuss all the items and Scott wanted to dig in on #8 briefly: - -The following API errors will either go away are become compile time errors: - -1. UNINITIALIZED_OBJECT – RAII idioms should ensure that only constructed objects are used (anything else would be blatant programmer error) -2. NULL_POINTER – no pointers should be used (but if they are it is on the programmer) -3. DOMAIN_MISMATCH – this is replaced by the compilers ability to reason about casting types (it can’t generate code if the casting is not supported or is ambiguous). - -Applying to the following is possible but would have significant impact on the design philosophy: - -4. DIMENSION_MISMATCH -o The only way to get the compiler to perform dimension checks is to make them part of the type of matrices and vectors. That basically means that the dimensions must be part of the template arguments. - This has been done in the C++ Standard Library with the array container (https://en.cppreference.com/w/cpp/container/array) -o Since the dimension becomes a compile time constant and cannot be changed, there would be no resizing in-place. -5. INVALID_INDEX: Getting the compiler to complain some of these errors would require the same change for Vector and Matrix methods that get, set and remove single elements. -o In the case of extract or assign operations, however, making this a compile-time error is not possible (the values must support being set at runtime) - -The following I believe cannot be caught by the compiler because they are dependent on the runtime data or something else: - -6. OUTPUT_NOT_EMPTY – data dependent -7. INVALID_VALUE – most instances are runtime data dependent -8. NOT_IMPLEMENTED – survives for obvious reasons if the implementers need wiggle room - -Ben responded with some additions: - -Here's my take on these errors: I generally agree with everything you've outlined here in terms of the types of errors we should throw. In addition, I would propose that the specific errors we throw should be modeled closely after C++ STL data structures (`vector` and `map`). Personally I think just about everything should be an exception. These errors should be rare (typically the result of an incorrect program), and will likely never be caught by the user. - -I agree about DIMENSION_MISMATCH---it should trigger some kind of runtime error. I personally think this is a great use case for an exception, since this should happen rarely and almost never be caught. (examples: user multiplies the wrong two matrices by mistake; user tries to read in the wrong Matrix Market file and the dimensions don't match.) - -As for INVALID_INDEX, I think this should either throw an exception (as with the `at` method) or result in undefined behavior, as in `operator[]`. There are well-defined and understood behaviors here in `std::vector` and `std::unordered_map` that we can directly follow. - -INVALID_VALUE - I think the only place in which this survives might be if we disallow vectors and matrices of dimension 0. Personally I have no problem with matrices of dimension 0, in which case I think we might not need this. - -NOT_IMPLEMENTED - we could consider making this a compile-time warning. diff --git a/minutes/minutes-2022-07-19.md b/minutes/minutes-2022-07-19.md deleted file mode 100644 index ade5b2f..0000000 --- a/minutes/minutes-2022-07-19.md +++ /dev/null @@ -1,37 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - July 19, 2022 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -1. Catch up with Ben -2. Catch Ben up -3. Decide on SC22 for draft release - -## Minutes - -1. We have a lot to do prior to SC22 and will have to punt a number things “down the road.” If we want to have a complete draft. - - Latex vs Markdown was discussed (no progress) - -2. The C API subcommittee agrees with the need for a shared math spec so that the different language committees do not need to redefine that part - - Will Kimmerer wants to participate. - - We think maybe the first step is to extract the math from the C API spec and reorganize and unify with the “Mathematical Foundations…” paper - - Latex vs. HTML was discussed (no progress) - - Tim is to reach out to Jeremy Kepner to gauge interest in participating - - Scott is to create a new repo for the math spec and commit what he has done so far. - -3. Reducer concept discussion: - - We discussed the merits of various C++ concepts for the reducer operator on GraphBLAS operations like mxm. - - The pros and cons of just leaving it BinaryOp and documenting in prose that if commutativity and associativity is violated then undefined behaviour results. - - The pros and cons of Commutative or Associative tags was discussed. - - If we go this route the spec needs to enumerate all of the operators (composed with three types) that satisfy these properties - - Ben also pointed out that some in the C++ community are also grappling with the definition of similar concepts. - - The consensus was to “punt” on the math property tags for now and define undefined behaviour, and wait to see if we can borrow from potential standardized items in the future to prohibit compilation rather than allow UB. - - No action items were discussed before the meeting abruptly ended due to time. - - diff --git a/minutes/minutes-2022-07-26.md b/minutes/minutes-2022-07-26.md deleted file mode 100644 index 2107543..0000000 --- a/minutes/minutes-2022-07-26.md +++ /dev/null @@ -1,23 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - July 26, 2022 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -1. Reviewed the current set of concepts - -## Minutes - -The following concepts were reviewed - -1. Binary Operator - T x U --> V -2. Monoid - T x T --> T, with an identity() value -3. MatrixRange (was ConstMatrixView): an immutable matrix or view of a matrix -4. MutableMatrixRange (was MatrixView: a matrix or matrix view whose contents are mutable. Existing values can be changed. - - Question: can new locations be stored or existing locations annihilated? -5. MaskMatrixRange: A MatrixRange whose elements are convertible to bool or boolean testable? diff --git a/minutes/minutes-2022-08-02.md b/minutes/minutes-2022-08-02.md deleted file mode 100644 index bcc7622..0000000 --- a/minutes/minutes-2022-08-02.md +++ /dev/null @@ -1,37 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - August 2, 2022 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan -- [ ] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda - -1. Reviewed the writeup for the current set of concepts, and present some of the views - -## Minutes - -The following concepts were reviewed. -- It was noted that these are wrappers around matrix objects with storage and any mutations done to the underlying container would be reflected in the view. -- Question: would any structure changing mutations to the underlying object also invalidate the iterators on the view. - -1. `grb::transpose_view<[Mutable]MatrixRange M> grb::transpose(M&&)` - - this can currently take and produce a MutableMatrixRange. That means that the output matrix could be transposed in this fashion which doubles the number of possible code paths to implement efficiently (but it does not necessarily double the amount of code). -2. `grb::transform_view grb::transform(M&&, Fn&&)` - - This is like a functional apply operation and support index unary operators. - - It does not produce a mutable view -3. `grb::structure_view grb::structure(M&&)` (there is a Vector variant) - - iterators on a structure view return all stored locations in the underlying matrix with the explicity value `true' -4. `grb::complement_view grb::complement(M&&)` (there is a Vector variant) - - A longer discussion was held regarding which elements should be iterated over in a complement view. - - Scott pointed out that the C API already defined a 'concept' for masks: the contents of a mask, M (denoted L(M)) in the C API spec was defined as only those elements that allow writing. - - If we carry the C API definition of the mask concept over to the C++ API, then an iterator over a complement_view will visit all locations that: - - did not have a stored value in the underlying matrix - - had a stored value in the underlying matrix that evaluated to false - - Question: why does this view only take MaskMatrixRange? - -## Postmortem - -The part of the discussion on complement_view about the concept of a Mask in the C API begs the question of whether we need a vanilla mask_view for default masks that skip stored `false`s? diff --git a/minutes/minutes-2022-09-01.md b/minutes/minutes-2022-09-01.md deleted file mode 100644 index f33d85a..0000000 --- a/minutes/minutes-2022-09-01.md +++ /dev/null @@ -1,58 +0,0 @@ -# GraphBLAS C++ Subcommittee Meeting - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -We are planning to begin an *internal review phase* early next week. The goal is to have language committee members read through the spec document. We will then use that feedback to direct any changes ahead of a somewhat broader *external review phase* in the coming weeks ahead. - -Rules for the *internal review phase*: - -1. Focus on functionality. Is there functionality in the C++ spec that is missing? - -2. Focus on expressiveness. Is there functionality that is there, but is cumbersome to use? Is there a way to express things better? - -3. Make notes about naming. This is the least important aspect at this point, but note down names that you think could be improved for later discussion. - -4. Make notes about implementation. This is also a somewhat secondary issue at this point, but are there parts of the API that should be modified to make writing a fast implementation easier? - -## Minutes - -List of features to add to the API: - -#### Critical (Functionality) - -- [ ] Variants of `multiply`, `ewise_union`, and `ewise_intersection` that accept an output matrix - -- [ ] Write introduction - -- [X] Submatrix view - -- [ ] Assign with mask as parameter? (Or should we let `mask_view` handle this?) - -- [X] Add `erase` to `matrix` and `vector` - -#### Minor - -- [ ] Update views in the spec to mirror `std::ranges::views` - -- [X] Define `grb::begin()`, `grb::end()`, `grb::find()`, `grb::insert()` in spec. - -- [ ] Better specify CPOs. - -### TODOs / Deliverables - -- Look through matrix and vector methods in C API for missing functionality in C++ API - -- Consider fill constructor for matrix and vector - -- Scott to look at introduction / math material - -#### Minor - -- Aliasing issue with assign (assigning to self) - -- Passing in Rvalue to range adapter - diff --git a/minutes/minutes-2022-09-08.md b/minutes/minutes-2022-09-08.md deleted file mode 100644 index 880efd3..0000000 --- a/minutes/minutes-2022-09-08.md +++ /dev/null @@ -1,34 +0,0 @@ -# GraphBLAS C++ Subcommittee Meeting - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- [X] Add way to retrieve version - -- [X] Multiply, ewise with output parameter - -- [X] Multiply, ewise for vector, etc. - -- [ ] Write intro - * One of the top priorities - -- [ ] Reduction - - * This should be easy to implement, once we settle on an API. - `std::ranges::reduce(grb::values_view(x));` - -- [ ] Write tests - -- [ ] Trace - -- [ ] Input/output, serialization - -- [ ] Kronecker product - -## Minutes - -### TODOs / Deliverables - diff --git a/minutes/minutes-apr-22-2021.md b/minutes/minutes-apr-22-2021.md deleted file mode 100644 index 9b68728..0000000 --- a/minutes/minutes-apr-22-2021.md +++ /dev/null @@ -1,47 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - April 22, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- Discuss - -## Minutes - -**Minutes** by Ben Brock - -- Sphinx's restructed text is not mature enough to write directly -- Header files -> Doxygen -> Sphinx output is not satisfactory for a standard - (although it would be fine for an implementation, and we probably should use it for a reference to have documentation) - -- find() -> does not except, will return end() even if indices outside bounds -- operator[] -> should not except (probably), may have undefined behavior if indices outside bounds - -- at() -> should except if outside bounds, accept if no value - -- begin() -- end() - -- constructors - -- could use matrix views for importing from raw pointer data - -- Agreement that we should crystalize this small number of methods, - which is limited but relatively complete, then move quickly to vector and - then algorithms. - -### Algorithms to Consider: - -- mxm - -- mxv - -- apply - -- reduce - -- select - -- extract diff --git a/minutes/minutes-apr-29-2021.md b/minutes/minutes-apr-29-2021.md deleted file mode 100644 index 5f34558..0000000 --- a/minutes/minutes-apr-29-2021.md +++ /dev/null @@ -1,32 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - April 29, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- Briefly discuss Matrix / Vector API drafts in standard document. - -- Discuss API for mxm - -## Minutes - -- Went over `grb::matrix` and `grb::vector` classes as implemented, discussing several issues. - -1. Currently, we impose the limit that the number of stored values must be strictly less than `std::numeric_limits::max()`, or else undefined behavior may occur (e.g. `index_type` must be able to reference all stored values). In addition, we require that `std::max(shape[0], shape[1]) < std::numeric_limits::max()` (The indices must fit in the index type. This one is totally unavoidable.). At an implementation level, this means that for types like CSR where one array refers to indices in the stored values array and one directly contains indices, both will contain values of type `index_type`. In cases where nnz >> n, it may be desired to use a larger type only for the arrays which refer to locations in the values array (e.g. rowptr in CSR), while using a smaller type for values that contain indices (e.g. colind in CSR). We could do this by adding an extra template parameter or simply always using `std::size_t` for arrays that point to stored values. The second one seems like the most consistent with C++ STL conatiners, since they guarantee (from an indices perspective) that they can hold up to `std::size_t` values. However, this has the possible disadvantage that it still requires the underlying backend to support operations where different index types are used at the same time. This is supported by at least one industry-standard sparse matrix libraries (like CuSPARSE), but not supported by many others (MKL, IBM's ESSL). It seems dangerous to preclude from using MKL as a backend from the start. - -2. `grb::matrix<...>::reference` is a valid C++ reference to `value_type`, where `value_type` is the type of the stored value. This means it has a conversion operator to `value_type` (allows reading from value) and an assignment operator to `value_type` (allows writing to the value). However, in addition, you can call the `index` function to return the index of the nonzero. There is also a conversion operator to `grb::index_t`, which allows retrieving the indices with a statement like `grb::index_t index = *iterator`. This is somewhat nonstandard, and presents a ambiguity issue if we are to make the index type of `grb::vector` scalar. - - Scott suggested that we should use iterator adaptors to resolve this issue. Scott will provide details on this in the next meeting. - - Ben suggests that the most "C++" way to solve this would be modifying the `value_type` to be an `std::tuple` include the indices, as in `unordered_map`, but this would make the API significantly more annoying to use. - - There is actually some precedent for augmenting iterators with access to indices, in Eigen [https://gallery.rcpp.org/articles/sparse-iterators/]. So this strategy of an "augmented reference" may not be that unorthodox. Ben feels strongly that the current user syntax is good, and we should try to maintain it. - -3. If we choose to implement a non-blocking mode, we would likely do so using `future` objects that are returned instead of the defaults. (e.g. `future operator[](grb::index_t)`) With futures, we would need to decide what errors would be thrown on function invocation and what might be thrown from inside the future (presumably on calling `wait` or `get`). - -4. We discussed `mxm`. There are a *lot* of mask variations, so this very well may require a descriptor. - -## TODO - -- Ben will implement a draft of `mxv` for next time. -- Scott will do some research about iterator adaptors for accessing indices. -- Both will think about possible alternatives to using a descriptor in `mxm`. diff --git a/minutes/minutes-jan-13-2022.md b/minutes/minutes-jan-13-2022.md deleted file mode 100644 index 6ae3262..0000000 --- a/minutes/minutes-jan-13-2022.md +++ /dev/null @@ -1,32 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - January 13, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -## Minutes -Discussed parts of C++ API left to include in draft. - -- Views - * transpose - * complement - * structure - * transform - * filter - * (submatrix views) - -- element-wise - * ewise_add - * ewise_multiply - (intersection / union??) - -extract arbitrary submatrix, - assign arbitrary submatrix -- extract -- assign - - -## TODOs -- Outline for GrAPL paper. diff --git a/minutes/minutes-jul-08-2021.md b/minutes/minutes-jul-08-2021.md deleted file mode 100644 index 6578097..0000000 --- a/minutes/minutes-jul-08-2021.md +++ /dev/null @@ -1,17 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - July 8, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -## Minutes - -- Discussed progress on the spec document. Ben is working on (1) named requirements for binary operators, monoids and (2) the matrix data structure. Ben put up documentation for his [RGRI C++ stuff](https://github.com/BenBrock/rgri). - -- Scott is working on writing up MXM in the spec. - -- Discussed GRB hints. Reached a consensus that hints should likely include `grb::sparse`, `grb::dense`, `grb::row` and `grb::column`, which can be combined to hint at various backend data structures, but do not guarantee anything. In order to avoid messiness, they can be combined using a `grb::compose` struct (e.g. `grb::compose`), which will then provide access to all the hints used in the backend like the parameter pack data structure in [Ben's futar code](https://github.com/BenBrock/futar/blob/master/futar/detail/detail.hpp#L46). (This underlying template behavior is NOT defined in the spec, just the hints and the API for `grb::compose`). - -- Discussed the issue about index parameters. There are at most two separate indices, one used to reference element indices (so it will limit the *dimension* of the matrix) and one used to reference locations in data structures (so that will limit the *number of stored values*). diff --git a/minutes/minutes-jul-15-2021.md b/minutes/minutes-jul-15-2021.md deleted file mode 100644 index a7d655a..0000000 --- a/minutes/minutes-jul-15-2021.md +++ /dev/null @@ -1,41 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - July 15, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda -Discuss Scott's draft of mxm, discuss Ben's draft of bin op, monoid, and matrix. - -## Minutes - -- Went over Scott's mxm, Ben's draft of binop and monoid, matrix. - -- Action item for Scott: take a look at cppreference's `std::transform` [here](https://en.cppreference.com/w/cpp/algorithm/transform). - -- Action item for Ben: flesh out matrix, as well as named requirements for MatrixReference and MatrixIterator. - -```c++ - // Get a reference to matrix element {12, 12} - // grb::matrix matrix = ...; - auto ref = matrix[{12, 12}]; - - float value = ref; - ref = 12.0f; - - matrix[{12, 12}] = 12; - float value = matrix[{13, 12}]; - - grb::index_t index = matrix[{12, 12}]; - - grb::index_t can be converted to std::tuple - - auto [i, j] = ref; - - auto [i, j, v] = ref; - - std::transform(matrix.begin(), matrix.end(), [](auto i, auto j, auto v) { - - std::reduce(matrix.begin(), matrix.end()); - -``` diff --git a/minutes/minutes-jun-03-2021.md b/minutes/minutes-jun-03-2021.md deleted file mode 100644 index 7f2b4cc..0000000 --- a/minutes/minutes-jun-03-2021.md +++ /dev/null @@ -1,12 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - June 3, 2021 - -## Attendees -- [ ] Ben Brock -- [ ] Scott McMillan - -## Agenda - -- Dsicuss Semirings and monoids -- Discuss what Scott found about iterator adaptors. - -## Minutes diff --git a/minutes/minutes-may-06-2021.md b/minutes/minutes-may-06-2021.md deleted file mode 100644 index 1f3fc98..0000000 --- a/minutes/minutes-may-06-2021.md +++ /dev/null @@ -1,32 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - May 6, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- Discuss what Scott found about iterator adaptors. -- Go over Ben's mxv draft implementation. - -## Minutes - -- Went over Ben's analysis of MXM. - -- Agreed that all facilities of the C API's `GrB_Matrix_mxm` can be achieved with the generic operation `C = mask(op(AB, C)) U merge(~mask(C))`. - -- This will have an API similar to the below, but likely with parameter order swapped. - -``` -void mxm(MatrixA A, MatrixB B, MatrixC C, - Mask mask - SemiR semiring, - Acc op, - bool merge = true); -``` - -- We agreed that we should include a `grb::mxm` function that hews closely to the C API, and likely an additional API that is simpler and more user-friendly. (Options include a NumPy-like `.dot()` API, although more experimentation is necessary.) - -## TODO -- Ben will get his `grb::mxv` implementation working. -- Scott will research and provide a take on iterator adaptors / Ben's current implementation of allowing references to provide indices. diff --git a/minutes/minutes-may-10-2022.md b/minutes/minutes-may-10-2022.md deleted file mode 100644 index d470608..0000000 --- a/minutes/minutes-may-10-2022.md +++ /dev/null @@ -1,29 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - May 10, 2022 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan -- [X] Tim Mattson -- [X] Aydin Buluc -- [X] Jose Moreira - -## Agenda -Discuss Jose Moreira's categorization of "sparse BLAS" and "semiring BLAS" - -## Minutes - -- Jose asserted that `ewiseAdd` and `ewiseMult` should not accept monoids or binary ops, as they lose their semantic meaning without a semiring. -- Instead, `ewiseUnion` and `ewiseIntersection` could accept binary ops, as well-defined set operations. - -![](assets/2022-05-10-120718_878x495_scrot.png) - -- Tim asserted that keeping an implied zero is a "longstanding practice in sparse linear algebra" that greatly simplifies things. -- The only reason `ewiseAdd` and `ewiseMult` make sense is because they correspond to that implied zero. - -- Ben suggested the creation of a third `ewise` operation, which would require placeholder (possibly "identity" values) for both matrices. This could be used to perform a subtraction (which is currently difficult in GrphBLAS). - -- Scott presented slides on matrix multiply, comparing lambda syntax with and without semirings. Using a semiring requires adding a `make_semiring` clause in `mxm`, versus having multiple arguments. - -- Scott suggests requiring the semiring just adds bulkiness to the call, which is inelegant. - -![](assets/2022-05-10-120147_1256x859_scrot.png) diff --git a/minutes/minutes-may-13.2021.md b/minutes/minutes-may-13.2021.md deleted file mode 100644 index f201b90..0000000 --- a/minutes/minutes-may-13.2021.md +++ /dev/null @@ -1,16 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - May 13, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- Discuss what Scott found about iterator adaptors. -- Go over Ben's mxv draft implementation. - -## Minutes - -- Went over Ben's mxv draft implementation. -- Agreed on the basic structure for mxv. -- Uncovered issue of types. Semiring has combiner `T x U -> V` and reducer `V x V -> V` diff --git a/minutes/minutes-may-24-2022.md b/minutes/minutes-may-24-2022.md deleted file mode 100644 index 7cf56bd..0000000 --- a/minutes/minutes-may-24-2022.md +++ /dev/null @@ -1,45 +0,0 @@ -# GraphBLAS Languages Committee Meeting (on C++ API) - May 24, 2022 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan -- [ ] Tim Mattson -- [ ] Aydin Buluc -- [X] Jose Moreira - -## Agenda -Discuss - -## Minutes - -- Discussed the possibility of doing a half-day tutorial at PACT. This would - be interactive and focus on the C++ API. - -- Scott presented slides on `ewise_add` for binary op and semiring. He proposed that the only real difference - between the semiring and binary op versions is the type of the user-provided op. - Using a semiring only makes things more bloated. - -![](assets/2022-05-24-121445_1358x652_scrot.png) - -- Jose stated that `ewise_add` is not meaningful outside of the context of a - "semiring BLAS," and that element-wise operations that operate using binary - ops should be considered as belonging to a "sparse BLAS" and kept separate - from "semiring BLAS" operations. - -- Ben and Scott then characterized today's debate as being about three central - questions: - -1. Does it make sense to call `ewise_add` without using a semiring (or monoid)? - Consensus (3/3): No. "Add" only makes sense because an identity is known, - thus allowing a semantic add to take place. Allowing binary ops results in - meaningless operations, such as `ewise_add` called with the `minus` op. This - is allowed (and well-defined) in the C API, but is considered unfortunate. - -2. Should semirings then exist at all in the API, if I can do everything using - a monoid (or a binary op with a hypothetical `ewise_union`)? - Mixed (2/3 yes, 1/3 undecided) - -3. Should there be some way to perform an element-wise subtraction in the API? - For example, a version of `ewise` that allows providing lefthand and righthand - placeholders to be used when no value exists? - Consensus (3/3): Probably. diff --git a/minutes/minutes-may-27-2021.md b/minutes/minutes-may-27-2021.md deleted file mode 100644 index 3327226..0000000 --- a/minutes/minutes-may-27-2021.md +++ /dev/null @@ -1,19 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - May 27, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda - -- Dsicuss Semirings and monoids -- Discuss what Scott found about iterator adaptors. - -## Minutes - -- Agreed on "issue of types and accumulation." - - Regardless of whether combiner and reducer are strictly typed, we can define `T x U -> V` based on the return type of `combiner(T(), U())`, where `T` and `U` are determined by A and B. Reduction will happen in type `V`, which may not necessarily correspond to the type of output C (could necessitate temporaries, but is mathematically correct). - -- Discussed Ben's idea for `monoid_traits` struct that inspects a functor of type `T` and defines an identity for the functor. For user- or library-defined types, this would be defining `identity` based on `identity` defined in the type `T`, but for other things (e.g. `std::plus<>`, `std::times<>`, etc.) could be defined separately. This corresponds very closely to how `std::iterator_traits` works. - -- There is still an open question of whether monoids (or binary ops that are "lifted" to monoids by having a specialization of `monoid_traits`) should be required to have a fixed type, and if not how the identity should be acquired (e.g. a template function / template struct). diff --git a/minutes/minutes-nov-10-2021.md b/minutes/minutes-nov-10-2021.md deleted file mode 100644 index fa1479f..0000000 --- a/minutes/minutes-nov-10-2021.md +++ /dev/null @@ -1,27 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - November 10, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda -- Discuss feedback from Andrew Lumsdaine related to range adaptors and potential interoperability between Graph Library and GraphBLAS. -- Discuss Ben's work on `grb::vector` interface -- Discuss some of Ben's backend matrix implementations -- Discuss complexities - -## Minutes -- Discussed potentially adding matrix range adaptors - * Would need to set guidelines for complexities - * Complexity of c'ting range adaptor - * Complexity of iteration through range adaptor -- Discussed Ben's `dense_vector` implementation - * Similar to matrix, except key is `I` integral instead of tuple-like `grb::index` - * `insert` and `insert_or_assign` vs `set_element`, `get_element`, etc. - * Ben thinks `insert` style is better and more standard - -## TODOs -- Ben will write up matrix entry in markdown a little more formally -- Experiment with LaTeX generation from markdown -- Ben will aim to fix up `grb::matrix`, write tests, concurrently with writing documentation -- Scott will review Ben's new markdown diff --git a/minutes/minutes-sep-16-2021.md b/minutes/minutes-sep-16-2021.md deleted file mode 100644 index d4be69b..0000000 --- a/minutes/minutes-sep-16-2021.md +++ /dev/null @@ -1,24 +0,0 @@ -# GraphBLAS C++ API Working Subgroup Meeting Minutes - September 16, 2021 - -## Attendees -- [X] Ben Brock -- [X] Scott McMillan - -## Agenda -- Discuss progress on named requirements hierarchy, view methods. - -- Discuss CppCon presentation. - -- Discuss SG19 meeting on P1709 graph proposal. - -## Minutes -- Discussed CppCon presentation. Will need to include a lot of background for C++ audience. Hope to have a few more points hammered down on our exact named requirements API, observations on how it might interact with graphs API. - -- Discussed SG19 meeting on P1709. P1709 focuses on creating concepts for iteration over graphs, which are 2D ranges. - * One key is that there are adaptors that are always used to retrieve the ranges (e.g. `vertices(G)`). This ensures that the API is distinct from the data structures. (Writing an adaptor could be complicated if your underlying data structure is not suitable for 2D iteration.) - * Ben thinks that we could allow for some interaction between the graph API and GraphBLAS, either by allowing their graph concepts to be usable in GraphBLAS or implementing GraphBLAS on top of their graph concepts. - -- Perhaps most importantly, discussed views and the named requirements they need to fulfill. We are currently encountering some difficulties deciding on the named requirements, since some of the restrictions on views are complex. - * The plan going in to the meeting was to define Matrix, ConstMatrix, ConstMatrixView, ConstStructureView, and MaskView types. - * Ben proposed loosening some of the restrictions on views, such as allowing ConstMatrixView to have (1) iteration and (2) element-wise access through `operator[]` and/or `find()`. - * Scott asked Ben to write up a new proposal with "promoted" views.