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.
This specification provides data structures for storing matrices and vectors. These implement the matrix and vector range concepts also defined in this specification.
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 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.
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.
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
.
// Define the `GRAPHBLAS_CPP_VERSION` macro to indicate
// conformance to the GraphBLAS 0.1 Draft Specification.
#define GRAPHBLAS_CPP_VERSION 202207L
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, 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?
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.
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;
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 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<T, I> , 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<T, I> |
const_reference |
grb::matrix_reference<const T, I> |
scalar_reference |
Reference to scalar_type |
const_scalar_reference |
Const reference to scalar_type |
hint_type |
Hint |
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
(const Allocator& alloc = Allocator()); (1)
matrix(grb::index<index_type> shape,
matrixconst Allocator& alloc = Allocator()); (2)
(const matrix& other); (3)
matrix(matrix&& other); (4) matrix
Constructs new grb::matrix
data structure.
0 x 0
.shape[0] x shape[1]
.other
.other
using move semantics. After the move,
other
is guaranteed to be empty.shape
- shape of the matrix to be constructed
other
- another matrix to construct the new matrix
from
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.
Linear in the size of the vector.
grb::matrix::operator=
& operator=(const matrix& other); (1)
matrix& operator=(matrix&& other); (2) matrix
Replaces the matrix with the contents and shape of another matrix.
other
and copies the stored values to be
the same as other
.other
using move semantics. After the move assignment
operation completes, other
is in a valid but indeterminate
state.other
- another matrix to assign the matrix to
Allocator::allocate
may throw.grb::matrix::size
size_type size() noexcept;
Returns the number of elements stored in the matrix.
(none)
Number of stored elements.
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.
(none)
Maximum possible number of elements.
Constant
grb::matrix::empty
bool empty() noexcept;
Returns whether the matrix is empty, that is where
size() == 0
.
(none)
Whether the matrix is empty.
Constant
grb::matrix::shape
::index<I> shape() const noexcept; grb
Returns the dimensions of the matrix.
(none)
Dimensions of the matrix.
Constant
grb::matrix::begin
and grb::matrix::cbegin
() noexcept;
iterator begin() const noexcept;
const_iterator begin() const noexcept; const_iterator cbegin
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()
.
(none)
Iterator to the first element
Constant
grb::matrix::end
and grb::matrix::cend
() noexcept;
iterator end() const noexcept;
const_iterator end() const noexcept; const_iterator cend
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.
(none)
Iterator to one past the last element.
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
shape
- New matrix shape
None
Implementation defined
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.
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.
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.
and (3) Insert the element value
if an element does
not already exist at the corresponding index in the matrix.
first
, last
- Range of elements to
insert
value
- element to insert
None
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.
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))
.
k
- the index location to assign obj
obj
- the scalar value to be assigned
M
must fulfill
std::is_assignable<scalar_type&, M>
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.
Implementation defined.
grb::matrix::erase
size_type erase(grb::index<I> index);
Erases the element stored at index index
if one
exists.
index
- the index of element to erase
Returns the number of elements erased (0 or 1).
Implementation defined.
grb::matrix::find
(grb::index<I> index);
iterator find(grb::index<I> index) const; const_iterator find
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()
.
index
- Location of the matrix element to find
An iterator pointing to the matrix element at the corresponding
index, or end()
if there is no element at the location.
Implementation defined
grb::matrix::operator[]
operator[](grb::index<I> index);
scalar_reference operator[](grb::index<I> index) const; const_scalar_reference
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.
index
- Location of the matrix element
A reference to the scalar value at location (index[0]
,
[index[1]
).
Implementation defined
grb::matrix::at
(grb::index<I> index);
scalar_reference at(grb::index<I> index) const; const_scalar_reference at
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
.
index
- Location of the matrix element
A reference to the scalar value at location (index[0]
,
[index[1]
).
Implementation defined
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;
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 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<T, I> , 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<T, I> |
const_reference |
grb::vector_ref<const T, I> |
scalar_reference |
Reference to scalar_type |
const_scalar_reference |
Const reference to scalar_type |
hint_type |
Hint |
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
(); (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) vector
Constructs new grb::vector
data structure.
shape
.shape
- shape of the vector to be constructed
May throw std::bad_alloc
.
grb::vector::size
size_type size() noexcept;
Returns the number of elements stored in the vector.
(none)
Number of stored elements.
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.
(none)
Maximum possible number of elements.
Constant
grb::vector::empty
bool empty() noexcept;
Returns whether the vector is empty, that is where
size() == 0
.
(none)
Whether the vector is empty.
Constant
grb::vector::shape
index_type shape() const noexcept;
Returns the dimension of the vector.
(none)
Dimension of the vector.
Constant
grb::vector::begin
and grb::vector::cbegin
() noexcept;
iterator begin() const noexcept;
const_iterator begin() const noexcept; const_iterator cbegin
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()
.
(none)
Iterator to the first element
Constant
grb::vector::end
and grb::vector::cend
() noexcept;
iterator end() const noexcept;
const_iterator end() const noexcept; const_iterator cend
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.
(none)
Iterator to one past the last element.
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.
shape
- New vector shape
None
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.
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.
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.
and (3) Insert the element value
if an element does
not already exist at the corresponding index in the vector.
first
, last
- Range of elements to
insert
value
- element to insert
None
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.
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))
.
k
- the index location to assign obj
obj
- the scalar value to be assigned
M
must fulfill
std::is_assignable<scalar_type&, M>
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.
Implementation defined.
grb::vector::erase
size_type erase(index_type index);
Erases the element stored at index index
if one
exists.
index
- the index of the scalar value to erase
Returns the number of elements erased (0 or 1).
Implementation defined.
grb::vector::find
(index_type index);
iterator find(index_type index) const; const_iterator find
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()
.
index
- Location of the vector element to find
An iterator pointing to the vector element at the corresponding
index, or end()
if there is no element at the location.
Implementation defined
grb::vector::operator[]
operator[](index_type index);
scalar_reference operator[](index_type index) const; const_scalar_reference
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.
index
- Location of the vector element
A reference to the scalar value at location index
.
Implementation defined
grb::vector::at
(index_type index);
scalar_reference at(index_type index) const; const_scalar_reference at
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
.
index
- Location of the vector element
A reference to the scalar value at location index
.
Implementation defined
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.
T
- type, satisfying std::integral
, used to
store indices
Member Type | Definition |
---|---|
index_type |
T |
first_type |
T |
second_type |
T |
Member Name | Type |
---|---|
first |
T |
second |
T |
Method | Description |
---|---|
(constructor) |
Constructs index |
operator[] |
Get one of the indices |
get |
Get one of the indices |
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.
#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.
::matrix<float, std::size_t, grb::dense> x({10, 10});
grb
// Create a matrix with the compile-time hint compose<sparse, row>.
// A GraphBLAS implementation may choose to employ a compressed sparse row
// storage format.
::matrix<float, std::size_t, grb::compose<grb::sparse, grb::row>> y({10, 10});
grb
// No change in data structure semantics is implied by a hint.
[{2, 3}] = 12;
x[{3, 6}] = 12;
x
[{6, 7}] = 1;
y[{6, 7}] = 2.5;
y
::print(x);
grb::print(y);
grb
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.
namespace views {
inline constexpr /* unspecified */ transpose = /* unspecified */;
}
template <MatrixRange M>
auto transpose(M&& matrix); MatrixRange
matrix
- a GraphBLAS matrix or matrix view
M
must meet the requirements of
MatrixRange
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.
namespace views {
inline constexpr /* unspecified */ transform = /* unspecified */;
}
template <MatrixRange M, std::copy_constructible Fn>
auto transform (M&& matrix, Fn&& fn); (1)
MatrixRange
template <VectorRange V, std::copy_constructible Fn>
auto transform(V&& vector, Fn&& fn); (2) VectorRange
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.
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.
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
M
must meet the requirements of
MatrixRange
V
must meet the requirements of
VectorRange
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
.
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
.
#include <grb/grb.hpp>
int main(int argc, char** argv) {
::matrix<float> a({10, 10});
grb
[{1, 2}] = 12.0f;
a[{3, 4}] = 123.2f;
a[{7, 8}] = 8.0f;;
a
::print(a, "original matrix");
grb
// 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;
});
::print(idx_view, "index transformed view");
grb
return 0;
}
template <MatrixRange M>
::structure_view<M> structure(M&& matrix); (1)
grb
template <VectorRange V>
::structure_view<V> structure(V&& vector); (2) grb
matrix
- a GraphBLAS matrix or matrix view
vector
- a GraphBLAS vector or vector view
matrix
must meet the requirements of
MatrixRange
vector
must meet the requirements of
VectorRange
inline constexpr bool always_true = [](auto&&) { return true; };
template <typename O>
using structure_view = grb::transform_view<O, decltype(always_true)>;
template <MatrixRange M>
::structure_view<M> structure(M&& matrix) {
grbreturn grb::transform(std::forward<M>(matrix), always_true);
}
template <VectorRange V>
::structure_view<V> structure(V&& vector) {
grbreturn grb::transform(std::forward<V>(vector), always_true);
}
template <MatrixRange M, typename Fn>
::filter_view<M> filter(M&& matrix, Fn&& fn); (1)
grb
template <VectorRange V, typename Fn>
::filter_view<V> filter(V&& vector, Fn&& fn); (2) grb
matrix
- a GraphBLAS matrix
vector
- a GraphBLAS vector
fn
- a function determining which elements should be
filtered out
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<M>
(1) or
std::ranges::value_type_t<V>
(2) and return a value
of type bool
.
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.
template <MaskMatrixRange M>
::complement_view<M> complement(M&& mask); (1)
grb
template <MaskVectorRange V>
::complement_view<V> complement(V&& mask); (2) grb
mask
- a GraphBLAS mask
M
must meet the requirements of
MaskMatrixRange
V
must meet the requirements of
MaskVectorRange
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.
Returns a matrix view satisfying the requirements
MaskMatrixRange
.
Returns a vector view satisfying the requirements
MaskVectorRange
.
template <MatrixRange Matrix, MaskMatrixRange M>
::masked_view<Matrix, M> mask(Matrix&& matrix, M&& mask); (1)
grb
template <VectorRange Vector, MaskVectorRange M>
::masked_view<Vector, M> mask(Vector&& vector, M&& mask); (2) grb
matrix
- a GraphBLAS matrix or vector
mask
- a GraphBLAS mask with the same shape as
matrix
(1) or vector
(2)
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)
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.
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.The exception grb::invalid_argument
is thrown if the
mask
does not have the same shape as matrix
(1) or vector
(2).
template <MatrixRange M>
::submatrix_view<M> submatrix(M&& matrix, grb::index<I> rows, grb::index<I> cols); grb
matrix
- a GraphBLAS matrix
rows
- the span of rows in the submatrix view
cols
- the span of columns in the submatrix view
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.
Returns the exception grb::invalid_argument
if
rows[0] > rows[1]
or
cols[0] > cols[1]
.
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.
They work the same way as binary operators, but are quite a bit simpler, since there is only one value to operate upon.
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:
op<T, U, V>
, where the input arguments are
explicitly specified to be T
and U
and the
return value is V
.op<T, U, void>
, where the input arguments are
explicitly specified to be T
and U
, and the
return value is deduced.op<void, void, void>
, where the inputs arguments
and return type are all deduced upon invocation.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.
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.
::plus<> p1;
grb
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;
}
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`.
::plus<int> p1;
grb
int a = 1024;
int b = 12;
// int + int -> int
int c = p1(a, b);
return 0;
}
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`.
::plus<std::size_t, std::uint8_t> p1;
grb
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;
}
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`.
::plus<std::size_t, std::uint8_t, int> p1;
grb
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.
Specialization | Description |
---|---|
plus<void, void, void> |
deduces argument and return types |
plus<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to sum
The result of lhs + rhs
.
May throw exceptions if the underlying operator+()
operation throws exceptions
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
.
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.
Specialization | Description |
---|---|
multiplies<void, void, void> |
deduces argument and return types |
multiplies<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to multiply
The result of lhs * rhs
.
May throw exceptions if the underlying operator*()
operation throws exceptions
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
.
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.
Specialization | Description |
---|---|
minus<void, void, void> |
deduces argument and return types |
minus<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to subtract
The result of lhs - rhs
.
May throw exceptions if the underlying operator-()
operation throws exceptions
grb::minus
does not form a monoid for arithmetic
types.
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.
Specialization | Description |
---|---|
divides<void, void, void> |
deduces argument and return types |
divides<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to divide
The result of lhs / rhs
.
May throw exceptions if the underlying operator/()
operation throws exceptions
grb::divides
does not form a monoid for arithmetic
types.
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.
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.
Specialization | Description |
---|---|
max<void, void, void> |
deduces argument and return types |
max<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to take the max of
The larger of lhs
and rhs
.
May throw exceptions if the underlying operator<()
operation throws exceptions
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
.
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()),
, T
U>;
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(),
, T
U>
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()),
, T
U>;
constexpr auto operator()(const T& a, const U& b) const
-> std::conditional_t<
std::numeric_limits<T>::max() < std::numeric_limits<U>::max(),
, T
U>
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.
Specialization | Description |
---|---|
min<void, void, void> |
deduces argument and return types |
min<T, U, void> |
deduces return type based on T and U |
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
Method | Description |
---|---|
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
.
lhs
, rhs
- values to take the min of
The smaller of lhs
and rhs
.
May throw exceptions if the underlying operator<()
operation throws exceptions
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
.
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()),
, T
U>;
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(),
, T
U>
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()),
, T
U>;
constexpr auto operator()(const T& a, const U& b) const
-> std::conditional_t<
std::numeric_limits<U>::lowest() < std::numeric_limits<T>::lowest(),
, T
U>
requires(!(std::is_integral_v<T> && std::is_integral_v<U>));
TODO: need “disablers” for all these CPOs. Also, “converted to its decayed type?”
grb::get
inline constexpr /* unspecified */ get = /* unspecified */;
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:
tuple.get<I>()
, if that expression is valid.get(tuple)
found through
argument-dependent lookup.std::get<I>(tuple)
.In all other cases, a call to grb::get
is
ill-formed.
grb::size
template <typename T>
inline constexpr /* unspecified */ size = std::ranges::size;
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:
t.size()
, if that expression is valid.size(t)
, found through
argument-dependent lookup.In all other cases, a call to grb::size
is
ill-formed.
grb::shape
template <typename T>
inline constexpr /* unspecified */ shape = /* unspecified */;
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:
t.shape()
if that expression is valid.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
template <typename T>
inline constexpr /* unspecified */ find = /* unspecified */;
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:
r.find(t)
if that expression is valid.find(r, t)
found through
argument-dependent lookup.std::find(r, t)
, if that
expression is valid.In all other cases, a call to grb::find
is
ill-formed.
grb::insert
template <typename T>
inline constexpr /* unspecified */ insert = /* unspecified */;
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:
r.insert(t)
if that expression is valid.insert(r, t)
found through
argument-dependent lookup.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>>
::matrix<T, I, Hint, Allocator>
grb(std::string file_path); read_matrix
Constructs a new GraphBLAS matrix based on the contents of a file.
T
- type of scalar values stored in matrix
I
- type of matrix indices
Hint
- compile-time hint for backend storage format.
Allocator
- allocator type
file_path
- string holding the file path of the matrix
to be read
Returns a GraphBLAS matrix whose dimensions and contents correspond
to the file located at file_path
.
Complexity is implementation-defined.
file_path
cannot be read, the exception
grb::matrix_io::file_error
is thrown.file_path
is recognized as an
unsupported format, the exception
grb::matrix_io::unsupported_file_format
is thrown.Allocator::allocate
may throw.GraphBLAS implementations must define the file formats that they support. Implementations are strongly encouraged to support the MatrixMarket format.
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
.
Fn
can be invoked with two arguments
of type T
and U
.V
.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>;
};
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.
// 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(); };
(fn, 12, 13);
apply}
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.
Fn
fulfills the concept
BinaryOperator<T, T, T>
for some type
T
.T
.T
,
accessible using
grb::monoid_traits<Fn, T>::identity()
.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 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.
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)
.T
is
accessible using std::tuple_element
, with the N’th stored
value equal to the N’th type in Types
.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
._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>>>());
// 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;
("%d, %d, %f\n", i, j, v);
printf}
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.
Entry
is a tuple-like type with a size of 2.Entry
is a tuple-like type fulfilling TupleLike<I, I>
,
storing the row and column index of the matrix entry.Entry
holds the matrix entry’s scalar value, and is convertible to
T
.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>; };
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.
Entry
, representing the
scalar value, is assignable to elements of type U
.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>;
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.
M
has a scalar type of the stored values, accessible
with grb::matrix_scalar_t<M>
M
has an index type used to reference the indices of
the stored values, accessible with
grb::matrix_index_t<M>
.M
is a range with a value type that represents a matrix
tuple, containing both the index and scalar value for each stored
value.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
.M
has a method find()
that takes an index
tuple and returns an iterator.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>,
::matrix_index_t<M>>;
grb{grb::shape(matrix)} -> Tuplelike<grb::matrix_index_t<M>,
::matrix_index_t<M>>;
grb{grb::find(matrix, {grb::matrix_index_t<M>{}, grb::matrix_index_t<M>{}})}
-> std::convertible_to<std::ranges::iterator_t<M>>;
};
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.
M
is a matrix range.M
fulfills the requirements of
MutableMatrixEntry<T, I>
.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.template <typename M, typename T>
concept MutableMatrixRange = MatrixRange<M> &&
<std::ranges::range_value_t<M>
MutableMatrixEntry::matrix_scalar_t<M>,
grb::matrix_index_t<M>,
grb> &&
Trequires(M matrix, T value) {
{grb::insert(matrix, {{grb::matrix_index_t<M>{}, grb::matrix_index_t<M>{}},
}) -> std::ranges::iterator_t<M>;
value}
};
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.
M
is a matrix range.M
is convertible to
bool
.template <typename M>
concept MaskMatrixRange = MatrixRange<M> &&
std::is_convertible_v<grb::matrix_scalar_t<M>, bool>;
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.
Entry
is a tuple-like type with a size of 2.Entry
fulfills std::integral
.Entry
holds the vector’s scalar value, and is convertible to
T
.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>; };
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.
Entry
, representing the
scalar value, is assignable to elements of type U
.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>;
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.
V
has a scalar type of the stored values, accessible
with grb::vector_scalar_t<V>
V
has an index type used to reference the indices of
the stored values, accessible with
grb::vector_index_t<V>
.V
is a range with a value type that represents a vector
tuple, containing both the index and scalar value for each stored
value.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
.V
has a method find()
that takes an index
and returns an iterator.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>,
::vector_index_t<V>>;
grb{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>>;
};
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.
V
is a vector range.M
fulfills the requirements of
MutableVectorEntry<T, I>
.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.template <typename V, typename T>
concept MutableVectorRange = VectorRange<V> &&
<std::ranges::range_value_t<V>,
MutableVectorEntry::vector_scalar_t<V>,
grb::vector_index_t<V>,
grb> &&
Trequires(V vector, T value) {
{grb::insert(vector, {grb::vector_index_t<V>{}, value})}
-> std::same_as<std::ranges::iterator_t<V>>;
};
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.
M
is a vector range.M
is convertible to
bool
.template <typename M>
concept MaskVectorRange = VectorRange<M> &&
std::is_convertible_v<grb::vector_scalar_t<M>, bool>;
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.
Fn
- type of commutative binary operator
T
- type on which Fn
forms a commutative
monoid
Member Type | Definition | Description |
---|---|---|
type |
T |
type of the monoid |
The default specialization has the following member functions:
Function | Description | |
---|---|---|
identity |
the identity value of the monoid |
grb::monoid_traits<Fn, T>::identity
static constexpr T identity() noexcept;
Returns the identity of the monoid.
None
Constant
May not throw exceptions
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>();
}
}
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.
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.
Exceptions may be thrown to indicate error conditions. A number of exceptions are defined which will be thrown in different error conditions.
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.
std::bad_alloc
. - Some functions and methods may
allocate memory using a user-provided allocator, which may throw.
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.
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
multiply_result_t<A, B, Reduce, Combine>
(A&& a, (1)
multiply&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine = grb::multiplies<>,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::combine_result_t<A, B, Combine>> C,
MutableMatrixRange<grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb>
void multiply(C&& c, (2)
&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
multiply_result_t<A, B, Reduce, Combine>
(ExecutionPolicy&& policy, (3)
multiply&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableMatrixRange>
void multiply(ExecutionPolicy&& policy, (4)
&& c,
C&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
template <MatrixRange A,
,
VectorRange B<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>
MaskVectorRange M >
<A, B, Reduce, Combine>
mutiply_result(A&& a, (5)
multiply&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <MatrixRange A,
,
VectorRange B<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine = grb::multiplies<>,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::combine_result_t<A, B, Combine>> C,
MutableVectorRange<grb::vector_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right<>
grb>
void multiply(C&& c, (6)
&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
template <typename ExecutionPolicy,
,
MatrixRange A,
VectorRange B<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>
MaskVectorRange M >
<A, B, Reduce, Combine>
mutiply_result(A&& a, (7)
multiply&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <typename ExecutionPolicy,
,
MatrixRange A,
VectorRange B<grb::matrix_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void multiply(C&& c, (8)
&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb>
<A, B, Reduce, Combine>
mutiply_result(A&& a, (9)
multiply&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{});
Combine
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb<grb::vector_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grbstd::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&& acc = Accumulate{},
Accumulatebool merge = false);
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb>
<A, B, Reduce, Combine>
mutiply_result(ExecutionPolicy&& policy, (11)
multiply&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{});
Combine
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb<grb::vector_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grbstd::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&& acc = Accumulate{},
Accumulatebool merge = false);
template <VectorRange A,
,
MatrixRange B<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>
MaskVectorRange M >
<A, B, Reduce, Combine>
mutiply_result(A&& a, (13)
multiply&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <VectorRange A,
,
MatrixRange B<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine = grb::multiplies<>,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce = grb::plus<>,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::combine_result_t<A, B, Combine>> C,
MutableVectorRange<grb::vector_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb>
void multiply(C&& c, (14)
&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
template <typename ExecutionPolicy,
,
VectorRange A,
MatrixRange B<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>
MaskVectorRange M >
<A, B, Reduce, Combine>
mutiply_result(ExecutionPolicy&& policy, (15)
multiply&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{});
M
template <typename ExecutionPolicy,
,
VectorRange A,
MatrixRange B<grb::vector_scalar_t<A>, grb::matrix_scalar_t<B>> Combine,
BinaryOperator<grb::combine_result_t<A, B, Combine>,
BinaryOperator::combine_result_t<A, B, Combine>,
grb::combine_result_t<A, B, Combine>> Reduce,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::vector_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void multiply(ExecutionPolicy&& policy, (16)
&& c,
C&& a,
A&& b,
B&& reduce = Reduce{},
Reduce&& combine = Combine{},
Combine&& mask = M{},
M&& acc = Accumulate{},
Accumulatebool merge = false);
Behavior is non-deterministic if reduce
is not
associative or not commutative.
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
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<A, B, Combine>, grb::combine_result_type_t<A, B, Combine>, grb::combine_result_type_t<A, B, Combine>>
Combine
must meet the requirements of
BinaryOperator<grb::container_value_t<A>, grb::container_value_t<B>>
M
must meet the requirements of
MaskMatrixRange
(1-8) or VectorMaskRange
(9-16)
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.shape()[0]
by
b.shape()[1]
a.shape()[0]
combine_result_t<A, B, Combine>
b.shape()[1]
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)))
.
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.
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.
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
.
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 is implementation-defined.
The exception grb::invalid_argument
may be thrown if any
of the following conditions occur:
a.shape()[1] != b.shape()[0]
.mask.shape()[0] < a.shape()[0] || mask.shape()[1] < b.shape()[1]
c.shape()[0] != a.shape()[0] || c.shape()[1] != b.shape()[1]
.a.shape()[1] != b.shape()
.mask.shape() < a.shape()[0]
c.shape() != a.shape()[0]
.a.shape() != b.shape()
.mask.shape() < a.shape()[0]
c.shape() != a.shape()[0]
.a.shape() != b.shape()[0]
.mask.shape() < b.shape()[1]
c.shape() != b.shape()[1]
.If the algorithm fails to allocate memory,
std::bad_alloc
is thrown.
ewise_union
Perform an element-wise union between two GraphBLAS matrices or vectors.
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
ewise_union_result_t<A, B, Combine>
(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (1)
ewise_union
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableMatrixRange>
void ewise_union(C&& c, A&& a, B&& b,
&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (2)
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
ewise_union_result_t<A, B, Combine>
(ExecutionPolicy&& policy,
ewise_union&& a, B&& b,
A&& combine, M&& mask = M{}); (3)
Combine
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableMatrixRange>
void ewise_union(ExecutionPolicy&& policy,
&& c, A&& a, B&& b,
C&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (4)
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t<A>,
BinaryOperator::vector_scalar_t<B>> Combine,
grb= grb::full_vector_mask<>
MaskVectorRange M >
ewise_union_result_t<A, B, Combine>
(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (5)
ewise_union
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void ewise_union(C&& c, A&& a, B&& b,
&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (6)
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t<A>,
BinaryOperator::vector_scalar_t<B>> Combine,
grb= grb::full_vector_mask<>
MaskVectorRange M >
ewise_union_result_t<A, B, Combine>
(ExecutionPolicy&& policy,
ewise_union&& a, B&& b,
A&& combine, M&& mask = M{}); (7)
Combine
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void ewise_union(ExecutionPolicy&& policy,
&& c, A&& a, B&& b,
C&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (8)
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
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<grb::combine_result_t<A, B, Combine>>
(2,4) or
MutableVectorRange<grb::combine_result_t<A, B, Combine>>
(6,8).
Combine
must meet the requirements of
BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>>
(1,2,3,4) or
BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>>
(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::matrix_scalar_t<C>, grb::combine_result_t<A, B, Combine>>
(2,4) or
BinaryOperator<grb::vector_scalar_t<C>, grb::combine_result_t<A, B, Combine>>
(6,8).
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])
.
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
.
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.
The exception grb::invalid_argument
may be thrown if any
of the following conditions occur:
a
and b
incompatible,
that is a.shape() != b.shape()
.c
, if given, does not match
a
’s shape, that is c.shape() != a.shape()
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).#include <grb/grb.hpp>
int main(int argc, char** argv) {
::matrix<float> x({10, 10});
grb::matrix<float> y({10, 10});
grb
[{0, 1}] = 12;
x[{2, 5}] = 12;
x[{2, 7}] = 12;
x[{5, 3}] = 12;
x
[{0, 1}] = 12;
y[{1, 5}] = 12;
y[{2, 7}] = 12;
y[{5, 3}] = 12;
y
auto z = grb::ewise_union(x, y, grb::plus{});
::print(z);
grb
return 0;
}
ewise_intersection
Perform an element-wise intersection between two GraphBLAS matrices or vectors.
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
ewise_intersection_result_t<A, B, Combine>
(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (1)
ewise_intersection
template <MatrixRange A,
,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableMatrixRange>
void ewise_intersection(C&& c, A&& a, B&& b,
&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (2)
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>
MaskMatrixRange M >
ewise_intersection_result_t<A, B, Combine>
(ExecutionPolicy&& policy,
ewise_intersection&& a, B&& b,
A&& combine, M&& mask = M{}); (3)
Combine
template <typename ExecutionPolicy,
,
MatrixRange A,
MatrixRange B<grb::matrix_scalar_t<A>,
BinaryOperator::matrix_scalar_t<B>> Combine,
grb= grb::full_matrix_mask<>,
MaskMatrixRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableMatrixRange>
void ewise_intersection(ExecutionPolicy&& policy,
&& c, A&& a, B&& b,
C&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (4)
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>
MaskVectorRange M >
ewise_intersection_result_t<A, B, Combine, M>
(A&& a, B&& b, Combine&& combine, M&& mask = M{}); (5)
ewise_intersection
template <VectorRange A,
,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void ewise_intersection(C&& c, A&& a, B&& b,
&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (6)
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>
MaskVectorRange M >
ewise_intersection_result_t<A, B, Combine, M>
(ExecutionPolicy&& policy,
ewise_intersection&& a, B&& b,
A&& combine, M&& mask = M{}); (7)
Combine
template <typename ExecutionPolicy,
,
VectorRange A,
VectorRange B<grb::vector_scalar_t_t<A>,
BinaryOperator::vector_scalar_t_t<B>> Combine,
grb= grb::full_vector_mask<>,
MaskVectorRange M <grb::matrix_scalar_t<C>,
BinaryOperator::combine_result_t<A, B, Combine>> Accumulate = grb::take_right,
grb<grb::combine_result_t<A, B, Combine>> C
MutableVectorRange>
void ewise_intersection(ExecutionPolicy&& policy,
&& c, A&& a, B&& b,
C&& combine, M&& mask = M{},
Combine&& acc = Accumulate{},
Accumulatebool merge = false); (8)
Perform an element-wise intersection.
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
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<grb::combine_result_t<A, B, Combine>>
(2,4) or
MutableVectorRange<grb::combine_result_t<A, B, Combine>>
(6,8).
Combine
must meet the requirements of
BinaryOperator<grb::matrix_scalar_t<A>, grb::matrix_scalar_t<B>>
(1,2,3,4) or
BinaryOperator<grb::vector_scalar_t<A>, grb::vector_scalar_t<B>>
(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::matrix_scalar_t<C>, grb::combine_result_t<A, B, Combine>>
(2,4) or
BinaryOperator<grb::vector_scalar_t<C>, grb::combine_result_t<A, B, Combine>>
(6,8).
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])
.
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
.
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.
The exception grb::invalid_argument
may be thrown if any
of the following conditions occur:
a
and b
incompatible,
that is a.shape() != b.shape()
.c
, if given, does not match
a
’s shape, that is c.shape() != a.shape()
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).#include <grb/grb.hpp>
int main(int argc, char** argv) {
::matrix<float> x({10, 10});
grb::matrix<float> y({10, 10});
grb
[{0, 1}] = 12;
x[{2, 5}] = 12;
x[{2, 7}] = 12;
x[{5, 3}] = 12;
x
[{0, 1}] = 12;
y[{1, 5}] = 12;
y[{2, 7}] = 12;
y[{5, 3}] = 12;
y
auto z = grb::ewise_intersection(x, y, grb::multiplies{});
::print(z);
grb
return 0;
}
assign
template <grb::MatrixRange B,
::MutableMatrixRange<grb::matrix_scalar_t<B>> A>
grbvoid 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,
::MutableVectorRange<grb::vector_scalar_t<V> U>
grbvoid 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.
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
A
must be a mutable matrix range for the scalar
value being assigned, that is it must meet the requirements of
grb::MutableMatrixRange<grb::matrix_scalar_t<B>>
(1) or grb::MutableMatrixRange<T>
(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<grb::vector_scalar_t<V>
(3) or grb::MutableVectorRange<T>
(4)
V
must meet the requirements of
grb::VectorRange
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
.