/* ----------------------------------------------------------------------- *//** * * @file EigenIntegration_impl.cpp * * @brief Convert between PostgreSQL types and Eigen types * *//* ----------------------------------------------------------------------- */ #ifndef MADLIB_POSTGRES_EIGEN_INTEGRATION_IMPL_HPP #define MADLIB_POSTGRES_EIGEN_INTEGRATION_IMPL_HPP namespace madlib { namespace dbal { namespace eigen_integration { // Specializations for DBMS-specific types // ------------------------------------------------------------------------ // HandleMap::HandleMap() // ------------------------------------------------------------------------ // eigen_integration::NativeMatrix /** * @brief Initialize HandleMap backed by the given handle * * In PostgreSQL, we represent a matrix as an array of columns. Therefore, the * index 0 is the number of columns, and index 1 is the number of rows. */ template <> inline HandleMap >::HandleMap( const ArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.sizeOfDim(1), inHandle.sizeOfDim(0)), mMemoryHandle(inHandle) { } // eigen_integration::MutableNativeMatrix /** * @brief Initialize HandleMap backed by the given handle * * In PostgreSQL, we represent a matrix as an array of columns. Therefore, the * index 0 is the number of columns, and index 1 is the number of rows. */ template <> inline HandleMap >::HandleMap( const MutableArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.sizeOfDim(1), inHandle.sizeOfDim(0)), mMemoryHandle(inHandle) { } // eigen_integration::NativeColumnVector /** * @brief Construct the HandleMap as one-dimensional vector * * This constructor uses size() method in ArrayHandle to determine the length. */ template <> inline HandleMap >::HandleMap( const ArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.size()), mMemoryHandle(inHandle) { } // eigen_integration::MutableNativeColumnVector /** * @brief Construct the HandleMap as one-dimensional vector * * This constructor uses size() method in ArrayHandle to determine the length. */ template <> inline HandleMap >::HandleMap( const MutableArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.size()), mMemoryHandle(inHandle) { } // eigen_integration::NativeIntegerVector /** * @brief Construct the HandleMap as one-dimensional vector * * This constructor uses size() method in ArrayHandle to determine the length. */ template <> inline HandleMap >::HandleMap( const ArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.size()), mMemoryHandle(inHandle) { } // eigen_integration::MutableNativeIntegerVector /** * @brief Construct the HandleMap as one-dimensional vector * * This constructor uses size() method in ArrayHandle to determine the length. */ template <> inline HandleMap >::HandleMap( const MutableArrayHandle& inHandle) : Base(const_cast(inHandle.ptr()), inHandle.size()), mMemoryHandle(inHandle) { } // ------------------------------------------------------------------------ // HandleMap::rebind() // ------------------------------------------------------------------------ // eigen_integration::NativeMatrix /** * @brief Rebind HandleMap to a different two-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const ArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(1), inHandle.sizeOfDim(0)); } // eigen_integration::MutableNativeMatrix /** * @brief Rebind HandleMap to a different two-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const MutableArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(1), inHandle.sizeOfDim(0)); } // eigen_integration::NativeColumnVector /** * @brief Rebind HandleMap to a different one-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const ArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(0)); } // eigen_integration::MutableNativeColumnVector /** * @brief Rebind HandleMap to a different one-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const MutableArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(0)); } // eigen_integration::NativeIntegerVector /** * @brief Rebind HandleMap to a different one-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const ArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(0)); } // eigen_integration::MutableNativeIntegerVector /** * @brief Rebind HandleMap to a different one-dimensional array */ template <> inline HandleMap >& HandleMap >::rebind( const MutableArrayHandle& inHandle) { return rebind(inHandle, inHandle.sizeOfDim(0)); } } // namespace eigen_integration } // namespace dbal namespace dbconnector { namespace postgres { /** * @brief Convert a run-length encoded Greenplum sparse vector to an Eigen * sparse vector * * @param inVec A Greenplum sparse vector * @returns Eigen sparse vector */ inline Eigen::SparseVector LegacySparseVectorToSparseColumnVector(SvecType* inVec) { SparseData sdata = sdata_from_svec(inVec); Eigen::SparseVector vec(sdata->total_value_count); char* ix = sdata->index->data; double* vals = reinterpret_cast(sdata->vals->data); int64_t logicalIdx = 0; for (int64_t physicalIdx = 0; physicalIdx < sdata->unique_value_count; ++physicalIdx) { int64_t runLength = compword_to_int8(ix); if (vals[physicalIdx] == 0.) { logicalIdx += runLength; } else { for (int64_t i = 0; i < runLength; ++i) vec.insertBack(static_cast(logicalIdx++)) = vals[physicalIdx]; } ix += int8compstoragesize(ix); } return vec; } /** * @brief Convert an Eigen sparse vector to a run-length encoded Greenplum * sparse vector * * @param inVec An Eigen sparse vector * @returns Greenplum sparse vector * * @internal We implement this function here and not in the legacy sparse-vector * code because the indices of type \c Index, as defined by Eigen. */ inline SvecType* SparseColumnVectorToLegacySparseVector( const Eigen::SparseVector &inVec) { typedef Eigen::SparseVector::Index Index; const size_t kValueLength = sizeof(double); const double* values = inVec.valuePtr(); const Index* indices = inVec.innerIndexPtr(); Index nnz = inVec.nonZeros(); Index size = inVec.size(); Index lastIndex = 0; double runValue = 0.; SparseData sdata = makeSparseData(); sdata->type_of_data = FLOAT8OID; madlib_assert(nnz == 0 || (indices && values), std::logic_error( "SparseColumnVectorToLegacySparseVector(): Missing values or indices " "in Eigen sparse vector.")); if (nnz > 0) { if (indices[0] == 0) { runValue = values[0]; } else if (std::memcmp(&values[0], &runValue, kValueLength)) { // In this case, we implicitly have: indices[0] > 0 // The first run is therefore a sequence of zeros. add_run_to_sdata(reinterpret_cast(&runValue), indices[0], kValueLength, sdata); runValue = values[0]; lastIndex = indices[0]; } // The remaining case is: indices[0] > 0 && values[0] == 0 // In this case, the original representation is not normalized -- // storing (indices[0], values[0]) is unncessary. We therefore just // ignore this value. } for (int i = 1; i < nnz; ++i) { if (std::memcmp(&values[i], &runValue, kValueLength)) { add_run_to_sdata(reinterpret_cast(&runValue), indices[i] - lastIndex, kValueLength, sdata); runValue = values[i]; lastIndex = indices[i]; } } add_run_to_sdata(reinterpret_cast(&runValue), size - lastIndex, kValueLength, sdata); // Add the final tallies sdata->unique_value_count = static_cast(sdata->vals->len / kValueLength); sdata->total_value_count = static_cast(size); return svec_from_sparsedata(sdata, true /* trim */); } // ------------------------------------------------------------------------ /** * @brief Convert an Eigen row or column vector to a one-dimensional * PostgreSQL array */ template ArrayType* VectorToNativeArray(const Eigen::MatrixBase& inVector) { typedef typename Derived::Scalar T; typedef typename Derived::Index Index; MutableArrayHandle arrayHandle = defaultAllocator().allocateArray(inVector.size()); T* ptr = arrayHandle.ptr(); for (Index el = 0; el < inVector.size(); ++el) *(ptr++) = inVector(el); return arrayHandle.array(); } /** * @brief Convert an Eigen matrix to a two-dimensional PostgreSQL array */ template ArrayType* MatrixToNativeArray(const Eigen::MatrixBase& inMatrix) { typedef typename Derived::Scalar T; typedef typename Derived::Index Index; MutableArrayHandle arrayHandle = defaultAllocator().allocateArray( inMatrix.cols(), inMatrix.rows()); T* ptr = arrayHandle.ptr(); // We use columnar storage, i.e., each column is a contiguous block for (Index col = 0; col < inMatrix.cols(); ++col) for (Index row = 0; row < inMatrix.rows(); ++row) *(ptr++) = inMatrix(row, col); return arrayHandle.array(); } /** * @brief Convert a native array to [Mutable]MappedVector */ template VectorType NativeArrayToMappedVector(Datum inDatum, bool inNeedMutableClone) { typedef typename VectorType::Scalar Scalar; ArrayType* array = reinterpret_cast( madlib_DatumGetArrayTypeP(inDatum)); size_t arraySize = ARR_NDIM(array) == 1 ? ARR_DIMS(array)[0] : ARR_DIMS(array)[0] * ARR_DIMS(array)[1]; if (!(ARR_NDIM(array) == 1 || (ARR_NDIM(array) == 2 && (ARR_DIMS(array)[0] == 1 || ARR_DIMS(array)[1] == 1)))) { std::stringstream errorMsg; errorMsg << "Invalid type conversion to matrix. Expected one-" "dimensional array but got " << ARR_NDIM(array) << " dimensions."; throw std::invalid_argument(errorMsg.str()); } Scalar* origData = reinterpret_cast(ARR_DATA_PTR(array)); Scalar* data; if (inNeedMutableClone) { data = reinterpret_cast( defaultAllocator().allocate(sizeof(Scalar) * arraySize)); std::copy(origData, origData + arraySize, data); } else { data = reinterpret_cast(ARR_DATA_PTR(array)); } return VectorType(data, arraySize); } /** * @brief Convert an Eigen VectorXcd to a two-dimensional PostgreSQL array */ template ArrayType* VectorXcdToNativeArray(const Eigen::MatrixBase& inMatrix) { typedef typename Derived::Scalar::value_type T; typedef typename Derived::Index Index; MutableArrayHandle arrayHandle = defaultAllocator().allocateArray( inMatrix.rows(), 2 /* for real and imag */); T* ptr = arrayHandle.ptr(); // We use columnar storage, i.e., each column is a contiguous block for (Index row = 0; row < inMatrix.rows(); ++row) { const std::complex &value = inMatrix(row, 0); *(ptr++) = value.real(); *(ptr++) = value.imag(); } return arrayHandle.array(); } /** * @brief Convert a native array to [Mutable]VectorXcd */ template VectorType NativeArrayToMappedVectorXcd(Datum inDatum, bool inNeedMutableClone) { typedef typename VectorType::Scalar Scalar; ArrayType* array = reinterpret_cast( madlib_DatumGetArrayTypeP(inDatum)); if (ARR_NDIM(array) != 2 || ARR_DIMS(array)[1] != 2) { std::stringstream errorMsg; errorMsg << "Invalid type conversion to VectorXcd. Expected two-" "dimensional array with two elements for secondary dimension " "but got " << ARR_NDIM(array) << " dimensions and " << ARR_DIMS(array)[1] << " elements in secondary dimension."; throw std::invalid_argument(errorMsg.str()); } size_t arraySize = ARR_DIMS(array)[0]; Scalar* origData = reinterpret_cast(ARR_DATA_PTR(array)); std::complex* data; if (inNeedMutableClone) { data = reinterpret_cast( defaultAllocator().allocate(sizeof(std::complex) * arraySize)); for (size_t i = 0; i < arraySize; ++i) { data[i] = std::complex(origData[0], origData[1]); origData += 2; } } else { data = reinterpret_cast*>(ARR_DATA_PTR(array)); } return VectorType(data, arraySize); } /** * @brief Convert a native array to [Mutable]MappedMatrix */ template MatrixType NativeArrayToMappedMatrix(Datum inDatum, bool inNeedMutableClone) { typedef typename MatrixType::Scalar Scalar; ArrayType* array = reinterpret_cast( madlib_DatumGetArrayTypeP(inDatum)); size_t arraySize = ARR_DIMS(array)[0] * ARR_DIMS(array)[1]; if (ARR_NDIM(array) != 2) { std::stringstream errorMsg; errorMsg << "Invalid type conversion to matrix. Expected two-" "dimensional array but got " << ARR_NDIM(array) << " dimensions."; throw std::invalid_argument(errorMsg.str()); } Scalar* origData = reinterpret_cast(ARR_DATA_PTR(array)); Scalar* data; if (inNeedMutableClone) { data = reinterpret_cast( defaultAllocator().allocate(sizeof(Scalar) * arraySize)); std::copy(origData, origData + arraySize, data); } else { data = reinterpret_cast(ARR_DATA_PTR(array)); } return MatrixType(data, ARR_DIMS(array)[1], ARR_DIMS(array)[0]); } } // namespace postgres } // namespace dbconnector } // namespace madlib #endif // defined(MADLIB_POSTGRES_EIGEN_INTEGRATION_IMPL_HPP)