/******************************************************* * Copyright (c) 2014, ArrayFire * All rights reserved. * * This file is distributed under 3-clause BSD license. * The complete license agreement can be obtained at: * http://arrayfire.com/licenses/BSD-3-Clause ********************************************************/ #include #include #include #include #include #include using af::dim4; using af::dtype_traits; using detail::Array; using detail::cdouble; using detail::cfloat; using detail::copyArray; using detail::createDeviceDataArray; using detail::createHostDataArray; using detail::createValueArray; using detail::getActiveDeviceId; using detail::scalar; using detail::writeDeviceDataArray; namespace common { //////////////////////////////////////////////////////////////////////////// // Sparse Array Base Implementations //////////////////////////////////////////////////////////////////////////// // ROW_LENGTH and column length expect standard variable names of // SparseArrayBase::stype // _nNZ -> Constructor Argument // _dims -> Constructor Argument #define ROW_LENGTH \ ((stype == AF_STORAGE_COO || stype == AF_STORAGE_CSC) ? _nNZ \ : (_dims[0] + 1)) #define COL_LENGTH \ ((stype == AF_STORAGE_COO || stype == AF_STORAGE_CSR) ? _nNZ \ : (_dims[1] + 1)) SparseArrayBase::SparseArrayBase(const af::dim4 &_dims, dim_t _nNZ, af::storage _storage, af_dtype _type) : info(getActiveDeviceId(), _dims, 0, calcStrides(_dims), _type, true) , stype(_storage) , rowIdx(createValueArray(dim4(ROW_LENGTH), 0)) , colIdx(createValueArray(dim4(COL_LENGTH), 0)) { static_assert(offsetof(SparseArrayBase, info) == 0, "SparseArrayBase::info must be the first member variable of " "SparseArrayBase."); static_assert(std::is_nothrow_move_assignable::value, "SparseArrayBase is not move assignable"); static_assert(std::is_nothrow_move_constructible::value, "SparseArrayBase is not move constructible"); } SparseArrayBase::SparseArrayBase(const af::dim4 &_dims, dim_t _nNZ, int *const _rowIdx, int *const _colIdx, const af::storage _storage, af_dtype _type, bool _is_device, bool _copy_device) : info(getActiveDeviceId(), _dims, 0, calcStrides(_dims), _type, true) , stype(_storage) , rowIdx(_is_device ? (!_copy_device ? createDeviceDataArray(dim4(ROW_LENGTH), _rowIdx) : createValueArray(dim4(ROW_LENGTH), 0)) : createHostDataArray(dim4(ROW_LENGTH), _rowIdx)) , colIdx(_is_device ? (!_copy_device ? createDeviceDataArray(dim4(COL_LENGTH), _colIdx) : createValueArray(dim4(COL_LENGTH), 0)) : createHostDataArray(dim4(COL_LENGTH), _colIdx)) { static_assert(offsetof(SparseArrayBase, info) == 0, "SparseArrayBase::info must be the first member variable of " "SparseArrayBase."); if (_is_device && _copy_device) { writeDeviceDataArray(rowIdx, _rowIdx, ROW_LENGTH * sizeof(int)); writeDeviceDataArray(colIdx, _colIdx, COL_LENGTH * sizeof(int)); } } SparseArrayBase::SparseArrayBase(const af::dim4 &_dims, const Array &_rowIdx, const Array &_colIdx, const af::storage _storage, af_dtype _type, bool _copy) : info(getActiveDeviceId(), _dims, 0, calcStrides(_dims), _type, true) , stype(_storage) , rowIdx(_copy ? copyArray(_rowIdx) : _rowIdx) , colIdx(_copy ? copyArray(_colIdx) : _colIdx) { static_assert(offsetof(SparseArrayBase, info) == 0, "SparseArrayBase::info must be the first member variable of " "SparseArrayBase."); } SparseArrayBase::SparseArrayBase(const SparseArrayBase &base, bool copy) : info(base.info) , stype(base.stype) , rowIdx(copy ? copyArray(base.rowIdx) : base.rowIdx) , colIdx(copy ? copyArray(base.colIdx) : base.colIdx) {} SparseArrayBase::~SparseArrayBase() = default; dim_t SparseArrayBase::getNNZ() const { if (stype == AF_STORAGE_COO || stype == AF_STORAGE_CSC) { return rowIdx.elements(); } if (stype == AF_STORAGE_CSR) { return colIdx.elements(); } // This is to ensure future storages are properly configured return 0; } #undef ROW_LENGTH #undef COL_LENGTH //////////////////////////////////////////////////////////////////////////// // Friend functions for Sparse Array Creation Implementations //////////////////////////////////////////////////////////////////////////// template SparseArray createEmptySparseArray(const af::dim4 &_dims, dim_t _nNZ, const af::storage _storage) { return SparseArray(_dims, _nNZ, _storage); } template SparseArray createHostDataSparseArray(const af::dim4 &_dims, const dim_t nNZ, const T *const _values, const int *const _rowIdx, const int *const _colIdx, const af::storage _storage) { return SparseArray(_dims, nNZ, const_cast(_values), const_cast(_rowIdx), const_cast(_colIdx), _storage, false); } template SparseArray createDeviceDataSparseArray( const af::dim4 &_dims, const dim_t nNZ, T *const _values, int *const _rowIdx, // NOLINT(readability-non-const-parameter) int *const _colIdx, // NOLINT(readability-non-const-parameter) const af::storage _storage, const bool _copy) { return SparseArray(_dims, nNZ, _values, _rowIdx, _colIdx, _storage, true, _copy); } template SparseArray createArrayDataSparseArray( const af::dim4 &_dims, const Array &_values, const Array &_rowIdx, const Array &_colIdx, const af::storage _storage, const bool _copy) { return SparseArray(_dims, _values, _rowIdx, _colIdx, _storage, _copy); } template SparseArray copySparseArray(const SparseArray &other) { return SparseArray(other, true); } template SparseArray *initSparseArray() { return new SparseArray(dim4(), 0, (af::storage)0); } template void destroySparseArray(SparseArray *sparse) { delete sparse; } //////////////////////////////////////////////////////////////////////////// // Sparse Array Class Implementations //////////////////////////////////////////////////////////////////////////// template SparseArray::SparseArray(const dim4 &_dims, dim_t _nNZ, af::storage _storage) : base(_dims, _nNZ, _storage, static_cast(dtype_traits::af_type)) , values(createValueArray(dim4(_nNZ), scalar(0))) { static_assert(std::is_standard_layout>::value, "SparseArray must be a standard layout type"); static_assert(std::is_nothrow_move_assignable>::value, "SparseArray is not move assignable"); static_assert(std::is_nothrow_move_constructible>::value, "SparseArray is not move constructible"); static_assert(offsetof(SparseArray, base) == 0, "SparseArray::base must be the first member variable of " "SparseArray"); } template SparseArray::SparseArray(const af::dim4 &_dims, dim_t _nNZ, T *const _values, int *const _rowIdx, int *const _colIdx, const af::storage _storage, bool _is_device, bool _copy_device) : base(_dims, _nNZ, _rowIdx, _colIdx, _storage, static_cast(dtype_traits::af_type), _is_device, _copy_device) , values(_is_device ? (!_copy_device ? createDeviceDataArray(dim4(_nNZ), _values) : createValueArray(dim4(_nNZ), scalar(0))) : createHostDataArray(dim4(_nNZ), _values)) { if (_is_device && _copy_device) { writeDeviceDataArray(values, _values, _nNZ * sizeof(T)); } } template SparseArray::SparseArray(const af::dim4 &_dims, const Array &_values, const Array &_rowIdx, const Array &_colIdx, const af::storage _storage, bool _copy) : base(_dims, _rowIdx, _colIdx, _storage, static_cast(dtype_traits::af_type), _copy) , values(_copy ? copyArray(_values) : _values) {} template SparseArray::SparseArray(const SparseArray &other, bool copy) : base(other.base, copy) , values(copy ? copyArray(other.values) : other.values) {} #define INSTANTIATE(T) \ template SparseArray createEmptySparseArray( \ const af::dim4 &_dims, dim_t _nNZ, const af::storage _storage); \ template SparseArray createHostDataSparseArray( \ const af::dim4 &_dims, const dim_t _nNZ, const T *const _values, \ const int *const _rowIdx, const int *const _colIdx, \ const af::storage _storage); \ template SparseArray createDeviceDataSparseArray( \ const af::dim4 &_dims, const dim_t _nNZ, \ T *const _values, /* NOLINT */ \ int *const _rowIdx, int *const _colIdx, const af::storage _storage, \ const bool _copy); \ template SparseArray createArrayDataSparseArray( \ const af::dim4 &_dims, const Array &_values, \ const Array &_rowIdx, const Array &_colIdx, \ const af::storage _storage, const bool _copy); \ template SparseArray *initSparseArray(); \ template SparseArray copySparseArray(const SparseArray &other); \ template void destroySparseArray(SparseArray * sparse); \ \ template SparseArray::SparseArray(const af::dim4 &_dims, dim_t _nNZ, \ af::storage _storage); \ template SparseArray::SparseArray( \ const af::dim4 &_dims, dim_t _nNZ, T *const _values, /* NOLINT */ \ int *const _rowIdx, int *const _colIdx, const af::storage _storage, \ bool _is_device, bool _copy_device); \ template SparseArray::SparseArray( \ const af::dim4 &_dims, const Array &_values, \ const Array &_rowIdx, const Array &_colIdx, \ const af::storage _storage, bool _copy) // Instantiate only floating types INSTANTIATE(float); INSTANTIATE(double); INSTANTIATE(cfloat); INSTANTIATE(cdouble); #undef INSTANTIATE } // namespace common