fg::Plot3* setup_plot3(const af_array P, fg::PlotType ptype, fg::MarkerType mtype) { Array<T> pIn = getArray<T>(P); ArrayInfo Pinfo = getInfo(P); af::dim4 P_dims = Pinfo.dims(); DIM_ASSERT(0, Pinfo.ndims() == 1 || Pinfo.ndims() == 2); DIM_ASSERT(0, (P_dims[0] == 3 || P_dims[1] == 3) || (Pinfo.isVector() && P_dims[0]%3 == 0)); if(Pinfo.isVector()){ dim4 rdims(P_dims.elements()/3, 3, 1, 1); pIn.modDims(rdims); P_dims = pIn.dims(); } if(P_dims[1] == 3){ pIn = transpose(pIn, false); } T max[3], min[3]; copyData(max, reduce<af_max_t, T, T>(pIn, 1)); copyData(min, reduce<af_min_t, T, T>(pIn, 1)); ForgeManager& fgMngr = ForgeManager::getInstance(); fg::Plot3* plot3 = fgMngr.getPlot3(P_dims.elements()/3, getGLType<T>(), ptype, mtype); plot3->setColor(1.0, 0.0, 0.0); plot3->setAxesLimits(max[0], min[0], max[1], min[1], max[2], min[2]); plot3->setAxesTitles("X Axis", "Y Axis", "Z Axis"); copy_plot3<T>(pIn, plot3); return plot3; }
af_err af_replace_scalar(af_array a, const af_array cond, const double b) { try { ArrayInfo ainfo = getInfo(a); ArrayInfo cinfo = getInfo(cond); ARG_ASSERT(1, cinfo.getType() == b8); DIM_ASSERT(1, cinfo.ndims() == ainfo.ndims()); dim4 adims = ainfo.dims(); dim4 cdims = cinfo.dims(); for (int i = 0; i < 4; i++) { DIM_ASSERT(1, cdims[i] == adims[i]); } switch (ainfo.getType()) { case f32: replace_scalar<float >(a, cond, b); break; case f64: replace_scalar<double >(a, cond, b); break; case c32: replace_scalar<cfloat >(a, cond, b); break; case c64: replace_scalar<cdouble>(a, cond, b); break; case s32: replace_scalar<int >(a, cond, b); break; case u32: replace_scalar<uint >(a, cond, b); break; case s64: replace_scalar<intl >(a, cond, b); break; case u64: replace_scalar<uintl >(a, cond, b); break; case u8: replace_scalar<uchar >(a, cond, b); break; case b8: replace_scalar<char >(a, cond, b); break; default: TYPE_ERROR(2, ainfo.getType()); } } CATCHALL; return AF_SUCCESS; }
af_err af_matmul(af_array *out, const af_array lhs, const af_array rhs, const af_mat_prop optLhs, const af_mat_prop optRhs) { using namespace detail; try { ArrayInfo lhsInfo = getInfo(lhs, false, true); ArrayInfo rhsInfo = getInfo(rhs, true, true); if(lhsInfo.isSparse()) return af_sparse_matmul(out, lhs, rhs, optLhs, optRhs); af_dtype lhs_type = lhsInfo.getType(); af_dtype rhs_type = rhsInfo.getType(); if (!(optLhs == AF_MAT_NONE || optLhs == AF_MAT_TRANS || optLhs == AF_MAT_CTRANS)) { AF_ERROR("Using this property is not yet supported in matmul", AF_ERR_NOT_SUPPORTED); } if (!(optRhs == AF_MAT_NONE || optRhs == AF_MAT_TRANS || optRhs == AF_MAT_CTRANS)) { AF_ERROR("Using this property is not yet supported in matmul", AF_ERR_NOT_SUPPORTED); } if (lhsInfo.ndims() > 2 || rhsInfo.ndims() > 2) { AF_ERROR("matmul can not be used in batch mode", AF_ERR_BATCH); } TYPE_ASSERT(lhs_type == rhs_type); af_array output = 0; int aColDim = (optLhs == AF_MAT_NONE) ? 1 : 0; int bRowDim = (optRhs == AF_MAT_NONE) ? 0 : 1; DIM_ASSERT(1, lhsInfo.dims()[aColDim] == rhsInfo.dims()[bRowDim]); switch(lhs_type) { case f32: output = matmul<float >(lhs, rhs, optLhs, optRhs); break; case c32: output = matmul<cfloat >(lhs, rhs, optLhs, optRhs); break; case f64: output = matmul<double >(lhs, rhs, optLhs, optRhs); break; case c64: output = matmul<cdouble>(lhs, rhs, optLhs, optRhs); break; default: TYPE_ERROR(1, lhs_type); } std::swap(*out, output); } CATCHALL return AF_SUCCESS; }
af_err af_select(af_array *out, const af_array cond, const af_array a, const af_array b) { try { ArrayInfo ainfo = getInfo(a); ArrayInfo binfo = getInfo(b); ArrayInfo cinfo = getInfo(cond); if(cinfo.ndims() == 0) { return af_retain_array(out, cond); } ARG_ASSERT(2, ainfo.getType() == binfo.getType()); ARG_ASSERT(1, cinfo.getType() == b8); DIM_ASSERT(1, cinfo.ndims() == std::min(ainfo.ndims(), binfo.ndims())); dim4 adims = ainfo.dims(); dim4 bdims = binfo.dims(); dim4 cdims = cinfo.dims(); dim4 odims(1, 1, 1, 1); for (int i = 0; i < 4; i++) { DIM_ASSERT(1, cdims[i] == std::min(adims[i], bdims[i])); DIM_ASSERT(2, adims[i] == bdims[i] || adims[i] == 1 || bdims[i] == 1); odims[i] = std::max(adims[i], bdims[i]); } af_array res; switch (ainfo.getType()) { case f32: res = select<float >(cond, a, b, odims); break; case f64: res = select<double >(cond, a, b, odims); break; case c32: res = select<cfloat >(cond, a, b, odims); break; case c64: res = select<cdouble>(cond, a, b, odims); break; case s32: res = select<int >(cond, a, b, odims); break; case u32: res = select<uint >(cond, a, b, odims); break; case s64: res = select<intl >(cond, a, b, odims); break; case u64: res = select<uintl >(cond, a, b, odims); break; case s16: res = select<short >(cond, a, b, odims); break; case u16: res = select<ushort >(cond, a, b, odims); break; case u8: res = select<uchar >(cond, a, b, odims); break; case b8: res = select<char >(cond, a, b, odims); break; default: TYPE_ERROR(2, ainfo.getType()); } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
af_err af_cplx(af_array *out, const af_array in) { try { ArrayInfo info = getInfo(in); af_dtype type = info.getType(); if (type == c32 || type == c64) { AF_ERROR("Inputs to cplx2 can not be of complex type", AF_ERR_ARG); } af_array tmp; AF_CHECK(af_constant(&tmp, 0, info.ndims(), info.dims().get(), type)); af_array res; switch (type) { case f32: res = cplx<cfloat , float >(in, tmp, false); break; case f64: res = cplx<cdouble, double>(in, tmp, false); break; default: TYPE_ERROR(0, type); } AF_CHECK(af_destroy_array(tmp)); std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
af_err af_imag(af_array *out, const af_array in) { try { ArrayInfo info = getInfo(in); af_dtype type = info.getType(); if (type != c32 && type != c64) { return af_constant(out, 0, info.ndims(), info.dims().get(), type); } af_array res; switch (type) { case c32: res = getHandle(imag<float , cfloat >(getArray<cfloat >(in))); break; case c64: res = getHandle(imag<double, cdouble>(getArray<cdouble>(in))); break; default: TYPE_ERROR(0, type); } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
//Strong Exception Guarantee af_err af_copy_array(af_array *out, const af_array in) { try { ArrayInfo info = getInfo(in); const af_dtype type = info.getType(); if(info.ndims() == 0) { dim_t my_dims[] = {0, 0, 0, 0}; return af_create_handle(out, AF_MAX_DIMS, my_dims, type); } af_array res; switch(type) { case f32: res = copyArray<float >(in); break; case c32: res = copyArray<cfloat >(in); break; case f64: res = copyArray<double >(in); break; case c64: res = copyArray<cdouble >(in); break; case b8: res = copyArray<char >(in); break; case s32: res = copyArray<int >(in); break; case u32: res = copyArray<uint >(in); break; case u8: res = copyArray<uchar >(in); break; case s64: res = copyArray<intl >(in); break; case u64: res = copyArray<uintl >(in); break; case s16: res = copyArray<short >(in); break; case u16: res = copyArray<ushort >(in); break; default: TYPE_ERROR(1, type); } std::swap(*out, res); } CATCHALL return AF_SUCCESS; }
static void print(af_array arr) { const ArrayInfo info = getInfo(arr); T *data = new T[info.elements()]; af_array arrT; AF_CHECK(af_reorder(&arrT, arr, 1, 0, 2, 3)); //FIXME: Use alternative function to avoid copies if possible AF_CHECK(af_get_data_ptr(data, arrT)); const ArrayInfo infoT = getInfo(arrT); AF_CHECK(af_destroy_array(arrT)); std::ios_base::fmtflags backup = std::cout.flags(); std::cout << "[" << info.dims() << "]\n"; #ifndef NDEBUG std::cout <<" Offsets: ["<<info.offsets()<<"]"<<std::endl; std::cout <<" Strides: ["<<info.strides()<<"]"<<std::endl; #endif printer(std::cout, data, infoT, infoT.ndims() - 1); delete[] data; std::cout.flags(backup); }
af_err af_tile(af_array *out, const af_array in, const af::dim4 &tileDims) { try { ArrayInfo info = getInfo(in); af_dtype type = info.getType(); if(info.ndims() == 0) { return af_retain_array(out, in); } DIM_ASSERT(1, info.dims().elements() > 0); DIM_ASSERT(2, tileDims.elements() > 0); af_array output; switch(type) { case f32: output = tile<float >(in, tileDims); break; case c32: output = tile<cfloat >(in, tileDims); break; case f64: output = tile<double >(in, tileDims); break; case c64: output = tile<cdouble>(in, tileDims); break; case b8: output = tile<char >(in, tileDims); break; case s32: output = tile<int >(in, tileDims); break; case u32: output = tile<uint >(in, tileDims); break; case s64: output = tile<intl >(in, tileDims); break; case u64: output = tile<uintl >(in, tileDims); break; case s16: output = tile<short >(in, tileDims); break; case u16: output = tile<ushort >(in, tileDims); break; case u8: output = tile<uchar >(in, tileDims); break; default: TYPE_ERROR(1, type); } std::swap(*out,output); } CATCHALL; return AF_SUCCESS; }
//Strong Exception Guarantee af_err af_copy_array(af_array *out, const af_array in) { ArrayInfo info = getInfo(in); const unsigned ndims = info.ndims(); const af::dim4 dims = info.dims(); const af_dtype type = info.getType(); af_err ret = AF_ERR_ARG; ret = af_create_handle(out, ndims, dims.get(), type); if(ret != AF_SUCCESS) { return ret; } try { switch(type) { case f32: copyArray<float >(out, in); break; case c32: copyArray<cfloat >(out, in); break; case f64: copyArray<double >(out, in); break; case c64: copyArray<cdouble >(out, in); break; case b8: copyArray<char >(out, in); break; case s32: copyArray<int >(out, in); break; case u32: copyArray<unsigned>(out, in); break; case u8: copyArray<uchar >(out, in); break; default: ret = AF_ERR_NOT_SUPPORTED; break; } } CATCHALL return ret; }
af_err af_dot( af_array *out, const af_array lhs, const af_array rhs, const af_mat_prop optLhs, const af_mat_prop optRhs) { using namespace detail; try { ArrayInfo lhsInfo = getInfo(lhs); ArrayInfo rhsInfo = getInfo(rhs); if (optLhs != AF_MAT_NONE && optLhs != AF_MAT_CONJ) { AF_ERROR("Using this property is not yet supported in dot", AF_ERR_NOT_SUPPORTED); } if (optRhs != AF_MAT_NONE && optRhs != AF_MAT_CONJ) { AF_ERROR("Using this property is not yet supported in dot", AF_ERR_NOT_SUPPORTED); } DIM_ASSERT(1, lhsInfo.dims()[0] == rhsInfo.dims()[0]); af_dtype lhs_type = lhsInfo.getType(); af_dtype rhs_type = rhsInfo.getType(); if(lhsInfo.ndims() == 0) { return af_retain_array(out, lhs); } if (lhsInfo.ndims() > 1 || rhsInfo.ndims() > 1) { AF_ERROR("dot can not be used in batch mode", AF_ERR_BATCH); } TYPE_ASSERT(lhs_type == rhs_type); af_array output = 0; switch(lhs_type) { case f32: output = dot<float >(lhs, rhs, optLhs, optRhs); break; case c32: output = dot<cfloat >(lhs, rhs, optLhs, optRhs); break; case f64: output = dot<double >(lhs, rhs, optLhs, optRhs); break; case c64: output = dot<cdouble>(lhs, rhs, optLhs, optRhs); break; default: TYPE_ERROR(1, lhs_type); } std::swap(*out, output); } CATCHALL return AF_SUCCESS; }
af_err af_get_numdims(unsigned *nd, const af_array in) { try { ArrayInfo info = getInfo(in); *nd = info.ndims(); } CATCHALL return AF_SUCCESS; }
af_err af_get_numdims(unsigned *nd, const af_array in) { try { // Do not check for device mismatch ArrayInfo info = getInfo(in, false, false); *nd = info.ndims(); } CATCHALL return AF_SUCCESS; }
af_err af_sparse_matmul(af_array *out, const af_array lhs, const af_array rhs, const af_mat_prop optLhs, const af_mat_prop optRhs) { using namespace detail; try { common::SparseArrayBase lhsBase = getSparseArrayBase(lhs); ArrayInfo rhsInfo = getInfo(rhs); ARG_ASSERT(2, lhsBase.isSparse() == true && rhsInfo.isSparse() == false); af_dtype lhs_type = lhsBase.getType(); af_dtype rhs_type = rhsInfo.getType(); ARG_ASSERT(1, lhsBase.getStorage() == AF_STORAGE_CSR); if (!(optLhs == AF_MAT_NONE || optLhs == AF_MAT_TRANS || optLhs == AF_MAT_CTRANS)) { // Note the ! operator. AF_ERROR("Using this property is not yet supported in sparse matmul", AF_ERR_NOT_SUPPORTED); } // No transpose options for RHS if (optRhs != AF_MAT_NONE) { AF_ERROR("Using this property is not yet supported in matmul", AF_ERR_NOT_SUPPORTED); } if (rhsInfo.ndims() > 2) { AF_ERROR("Sparse matmul can not be used in batch mode", AF_ERR_BATCH); } TYPE_ASSERT(lhs_type == rhs_type); af::dim4 ldims = lhsBase.dims(); int lColDim = (optLhs == AF_MAT_NONE) ? 1 : 0; int rRowDim = (optRhs == AF_MAT_NONE) ? 0 : 1; DIM_ASSERT(1, ldims[lColDim] == rhsInfo.dims()[rRowDim]); af_array output = 0; switch(lhs_type) { case f32: output = sparseMatmul<float >(lhs, rhs, optLhs, optRhs); break; case c32: output = sparseMatmul<cfloat >(lhs, rhs, optLhs, optRhs); break; case f64: output = sparseMatmul<double >(lhs, rhs, optLhs, optRhs); break; case c64: output = sparseMatmul<cdouble>(lhs, rhs, optLhs, optRhs); break; default: TYPE_ERROR(1, lhs_type); } std::swap(*out, output); } CATCHALL; return AF_SUCCESS; }
af_err af_get_numdims(unsigned *nd, const af_array in) { af_err ret = AF_ERR_ARG; try { ArrayInfo info = getInfo(in); *nd = info.ndims(); ret = AF_SUCCESS; } CATCHALL return ret; }
af_err af_select_scalar_r(af_array *out, const af_array cond, const af_array a, const double b) { try { ArrayInfo ainfo = getInfo(a); ArrayInfo cinfo = getInfo(cond); ARG_ASSERT(1, cinfo.getType() == b8); DIM_ASSERT(1, cinfo.ndims() == ainfo.ndims()); dim4 adims = ainfo.dims(); dim4 cdims = cinfo.dims(); for (int i = 0; i < 4; i++) { DIM_ASSERT(1, cdims[i] == adims[i]); } af_array res; switch (ainfo.getType()) { case f32: res = select_scalar<float , false>(cond, a, b, adims); break; case f64: res = select_scalar<double , false>(cond, a, b, adims); break; case c32: res = select_scalar<cfloat , false>(cond, a, b, adims); break; case c64: res = select_scalar<cdouble, false>(cond, a, b, adims); break; case s32: res = select_scalar<int , false>(cond, a, b, adims); break; case u32: res = select_scalar<uint , false>(cond, a, b, adims); break; case s16: res = select_scalar<short , false>(cond, a, b, adims); break; case u16: res = select_scalar<ushort , false>(cond, a, b, adims); break; case s64: res = select_scalar<intl , false>(cond, a, b, adims); break; case u64: res = select_scalar<uintl , false>(cond, a, b, adims); break; case u8: res = select_scalar<uchar , false>(cond, a, b, adims); break; case b8: res = select_scalar<char , false>(cond, a, b, adims); break; default: TYPE_ERROR(2, ainfo.getType()); } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
af_err af_topk(af_array *values, af_array *indices, const af_array in, const int k, const int dim, const af_topk_function order) { try { af::topkFunction ord = (order == AF_TOPK_DEFAULT ? AF_TOPK_MAX : order); ArrayInfo inInfo = getInfo(in); ARG_ASSERT(2, (inInfo.ndims() > 0)); if (inInfo.elements() == 1) { dim_t dims[1] = {1}; af_err errValue = af_constant(indices, 0, 1, dims, u32); return errValue == AF_SUCCESS ? af_retain_array(values, in) : errValue; } int rdim = dim; auto &inDims = inInfo.dims(); if (rdim == -1) { for (dim_t d = 0; d < 4; d++) { if (inDims[d] > 1) { rdim = d; break; } } } ARG_ASSERT(2, (inInfo.dims()[rdim] >= k)); ARG_ASSERT(4, (k <= 256)); // TODO(umar): Remove this limitation if (rdim != 0) AF_ERROR("topk is supported along dimenion 0 only.", AF_ERR_NOT_SUPPORTED); af_dtype type = inInfo.getType(); switch (type) { // TODO(umar): FIX RETURN VALUES HERE case f32: topk<float>(values, indices, in, k, rdim, ord); break; case f64: topk<double>(values, indices, in, k, rdim, ord); break; case u32: topk<uint>(values, indices, in, k, rdim, ord); break; case s32: topk<int>(values, indices, in, k, rdim, ord); break; default: TYPE_ERROR(1, type); } } CATCHALL; return AF_SUCCESS; }
static void print(const char *exp, af_array arr, const int precision, std::ostream &os = std::cout, bool transpose = true) { if(exp == NULL) { os << "No Name Array" << std::endl; } else { os << exp << std::endl; } const ArrayInfo info = getInfo(arr); vector<T> data(info.elements()); af_array arrT; if(transpose) { AF_CHECK(af_reorder(&arrT, arr, 1, 0, 2, 3)); } else { arrT = arr; } //FIXME: Use alternative function to avoid copies if possible AF_CHECK(af_get_data_ptr(&data.front(), arrT)); const ArrayInfo infoT = getInfo(arrT); if(transpose) { AF_CHECK(af_release_array(arrT)); } std::ios_base::fmtflags backup = os.flags(); os << "[" << info.dims() << "]\n"; #ifndef NDEBUG os <<" Offsets: [" << info.offsets() << "]" << std::endl; os <<" Strides: [" << info.strides() << "]" << std::endl; #endif printer(os, &data.front(), infoT, infoT.ndims() - 1, precision); os.flags(backup); }
af_err af_index(af_array *result, const af_array in, const unsigned ndims, const af_seq* index) { af_array out; try { ArrayInfo iInfo = getInfo(in); if (ndims == 1 && ndims != (dim_t)iInfo.ndims()) { af_array tmp_in; AF_CHECK(af_flat(&tmp_in, in)); AF_CHECK(af_index(result, tmp_in, ndims, index)); AF_CHECK(af_release_array(tmp_in)); return AF_SUCCESS; } af_dtype in_type = iInfo.getType(); switch(in_type) { case f32: indexArray<float> (out, in, ndims, index); break; case c32: indexArray<cfloat> (out, in, ndims, index); break; case f64: indexArray<double> (out, in, ndims, index); break; case c64: indexArray<cdouble> (out, in, ndims, index); break; case b8: indexArray<char> (out, in, ndims, index); break; case s32: indexArray<int> (out, in, ndims, index); break; case u32: indexArray<unsigned>(out, in, ndims, index); break; case s16: indexArray<short> (out, in, ndims, index); break; case u16: indexArray<ushort> (out, in, ndims, index); break; case s64: indexArray<intl> (out, in, ndims, index); break; case u64: indexArray<uintl> (out, in, ndims, index); break; case u8: indexArray<uchar> (out, in, ndims, index); break; default: TYPE_ERROR(1, in_type); } } CATCHALL swap(*result, out); return AF_SUCCESS; }
af_err af_root(af_array *out, const af_array lhs, const af_array rhs, const bool batchMode) { try { ArrayInfo linfo = getInfo(lhs); ArrayInfo rinfo = getInfo(rhs); if (linfo.isComplex() || rinfo.isComplex()) { AF_ERROR("Powers of Complex numbers not supported", AF_ERR_NOT_SUPPORTED); } af_array one; AF_CHECK(af_constant(&one, 1, linfo.ndims(), linfo.dims().get(), linfo.getType())); af_array inv_lhs; AF_CHECK(af_div(&inv_lhs, one, lhs, batchMode)); AF_CHECK(af_arith_real<af_pow_t>(out, rhs, inv_lhs, batchMode)); AF_CHECK(af_release_array(one)); AF_CHECK(af_release_array(inv_lhs)); } CATCHALL; return AF_SUCCESS; }
static af_err reduce_promote(af_array *out, const af_array in, const int dim) { try { ARG_ASSERT(2, dim >= 0); ARG_ASSERT(2, dim < 4); const ArrayInfo in_info = getInfo(in); if (dim >= (int)in_info.ndims()) { *out = weakCopy(in); return AF_SUCCESS; } af_dtype type = in_info.getType(); af_array res; switch(type) { case f32: res = reduce<op, float , float >(in, dim); break; case f64: res = reduce<op, double , double >(in, dim); break; case c32: res = reduce<op, cfloat , cfloat >(in, dim); break; case c64: res = reduce<op, cdouble, cdouble>(in, dim); break; case u32: res = reduce<op, uint , uint >(in, dim); break; case s32: res = reduce<op, int , int >(in, dim); break; case u8: res = reduce<op, uchar , uint >(in, dim); break; case s8: res = reduce<op, char , int >(in, dim); break; // Make sure you are adding only "1" for every non zero value, even if op == af_add_t case b8: res = reduce<af_notzero_t, uchar , uint >(in, dim); break; default: TYPE_ERROR(1, type); } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
static af_err reduce_common(af_array *out, const af_array in, const int dim) { try { ARG_ASSERT(2, dim >= 0); ARG_ASSERT(2, dim < 4); const ArrayInfo in_info = getInfo(in); if (dim >= (int)in_info.ndims()) { *out = weakCopy(in); return AF_SUCCESS; } af_dtype type = in_info.getType(); af_array res; switch(type) { case f32: res = reduce<op, float , float >(in, dim); break; case f64: res = reduce<op, double , double >(in, dim); break; case c32: res = reduce<op, cfloat , cfloat >(in, dim); break; case c64: res = reduce<op, cdouble, cdouble>(in, dim); break; case u32: res = reduce<op, uint , uint >(in, dim); break; case s32: res = reduce<op, int , int >(in, dim); break; case b8: res = reduce<op, uchar , uchar >(in, dim); break; case u8: res = reduce<op, uchar , uchar >(in, dim); break; case s8: res = reduce<op, char , char >(in, dim); break; default: TYPE_ERROR(1, type); } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }
af_err af_index_gen(af_array *out, const af_array in, const dim_t ndims, const af_index_t* indexs) { af_array output = 0; // spanner is sequence index used for indexing along the // dimensions after ndims af_index_t spanner; spanner.idx.seq = af_span; spanner.isSeq = true; try { ARG_ASSERT(2, (ndims>0)); ARG_ASSERT(3, (indexs!=NULL)); ArrayInfo iInfo = getInfo(in); if (ndims == 1 && ndims != (dim_t)iInfo.ndims()) { af_array tmp_in; AF_CHECK(af_flat(&tmp_in, in)); AF_CHECK(af_index_gen(out, tmp_in, ndims, indexs)); AF_CHECK(af_release_array(tmp_in)); return AF_SUCCESS; } int track = 0; af_seq seqs[] = {af_span, af_span, af_span, af_span}; for (dim_t i = 0; i < ndims; i++) { if (indexs[i].isSeq) { track++; seqs[i] = indexs[i].idx.seq; } } if (track==(int)ndims) { // all indexs are sequences, redirecting to af_index return af_index(out, in, ndims, seqs); } af_index_t idxrs[4]; // set all dimensions above ndims to spanner index for (dim_t i=ndims; i<4; ++i) idxrs[i] = spanner; for (dim_t i=0; i<ndims; ++i) { if (!indexs[i].isSeq) { // check if all af_arrays have atleast one value // to enable indexing along that dimension ArrayInfo idxInfo = getInfo(indexs[i].idx.arr); af_dtype idxType = idxInfo.getType(); ARG_ASSERT(3, (idxType!=c32)); ARG_ASSERT(3, (idxType!=c64)); ARG_ASSERT(3, (idxType!=b8 )); idxrs[i].idx.arr = indexs[i].idx.arr; idxrs[i].isSeq = indexs[i].isSeq; } else { // af_seq is being used for this dimension // just copy the index to local variable idxrs[i] = indexs[i]; } } dim4 iDims = iInfo.dims(); ARG_ASSERT(1, (iDims.ndims()>0)); af_dtype inType = getInfo(in).getType(); switch(inType) { case c64: output = genIndex<cdouble>(in, idxrs); break; case f64: output = genIndex<double >(in, idxrs); break; case c32: output = genIndex<cfloat >(in, idxrs); break; case f32: output = genIndex<float >(in, idxrs); break; case u64: output = genIndex<uintl >(in, idxrs); break; case s64: output = genIndex<intl >(in, idxrs); break; case u32: output = genIndex<uint >(in, idxrs); break; case s32: output = genIndex<int >(in, idxrs); break; case u16: output = genIndex<ushort >(in, idxrs); break; case s16: output = genIndex<short >(in, idxrs); break; case u8: output = genIndex<uchar >(in, idxrs); break; case b8: output = genIndex<char >(in, idxrs); break; default: TYPE_ERROR(1, inType); } } CATCHALL; std::swap(*out, output); return AF_SUCCESS; }
// Save an image to memory. af_err af_save_image_memory(void **ptr, const af_array in_, const af_image_format format) { try { FI_Init(); // set your own FreeImage error handler FreeImage_SetOutputMessage(FreeImageErrorHandler); // try to guess the file format from the file extension FREE_IMAGE_FORMAT fif = (FREE_IMAGE_FORMAT)format; if(fif == FIF_UNKNOWN || fif > 34) { // FreeImage FREE_IMAGE_FORMAT has upto 34 enums as of 3.17 AF_ERROR("FreeImage Error: Unknown Filetype", AF_ERR_NOT_SUPPORTED); } ArrayInfo info = getInfo(in_); // check image color type uint channels = info.dims()[2]; DIM_ASSERT(1, channels <= 4); DIM_ASSERT(1, channels != 2); int fi_bpp = channels * 8; // sizes uint fi_w = info.dims()[1]; uint fi_h = info.dims()[0]; // create the result image storage using FreeImage FIBITMAP* pResultBitmap = FreeImage_Allocate(fi_w, fi_h, fi_bpp); if(pResultBitmap == NULL) { AF_ERROR("FreeImage Error: Error creating image or file", AF_ERR_RUNTIME); } // FI assumes [0-255] // If array is in 0-1 range, multiply by 255 af_array in; double max_real, max_imag; bool free_in = false; AF_CHECK(af_max_all(&max_real, &max_imag, in_)); if (max_real <= 1) { af_array c255; AF_CHECK(af_constant(&c255, 255.0, info.ndims(), info.dims().get(), f32)); AF_CHECK(af_mul(&in, in_, c255, false)); AF_CHECK(af_release_array(c255)); free_in = true; } else { in = in_; } // FI = row major | AF = column major uint nDstPitch = FreeImage_GetPitch(pResultBitmap); uchar* pDstLine = FreeImage_GetBits(pResultBitmap) + nDstPitch * (fi_h - 1); af_array rr = 0, gg = 0, bb = 0, aa = 0; AF_CHECK(channel_split(in, info.dims(), &rr, &gg, &bb, &aa)); // convert array to 3 channels if needed uint step = channels; // force 3 channels saving uint indx = 0; af_array rrT = 0, ggT = 0, bbT = 0, aaT = 0; if(channels == 4) { AF_CHECK(af_transpose(&rrT, rr, false)); AF_CHECK(af_transpose(&ggT, gg, false)); AF_CHECK(af_transpose(&bbT, bb, false)); AF_CHECK(af_transpose(&aaT, aa, false)); ArrayInfo cinfo = getInfo(rrT); float* pSrc0 = pinnedAlloc<float>(cinfo.elements()); float* pSrc1 = pinnedAlloc<float>(cinfo.elements()); float* pSrc2 = pinnedAlloc<float>(cinfo.elements()); float* pSrc3 = pinnedAlloc<float>(cinfo.elements()); AF_CHECK(af_get_data_ptr((void*)pSrc0, rrT)); AF_CHECK(af_get_data_ptr((void*)pSrc1, ggT)); AF_CHECK(af_get_data_ptr((void*)pSrc2, bbT)); AF_CHECK(af_get_data_ptr((void*)pSrc3, aaT)); // Copy the array into FreeImage buffer for (uint y = 0; y < fi_h; ++y) { for (uint x = 0; x < fi_w; ++x) { *(pDstLine + x * step + 2) = (uchar) pSrc0[indx]; // b *(pDstLine + x * step + 1) = (uchar) pSrc1[indx]; // g *(pDstLine + x * step + 0) = (uchar) pSrc2[indx]; // r *(pDstLine + x * step + 3) = (uchar) pSrc3[indx]; // a ++indx; } pDstLine -= nDstPitch; } pinnedFree(pSrc0); pinnedFree(pSrc1); pinnedFree(pSrc2); pinnedFree(pSrc3); } else if(channels == 3) { AF_CHECK(af_transpose(&rrT, rr, false)); AF_CHECK(af_transpose(&ggT, gg, false)); AF_CHECK(af_transpose(&bbT, bb, false)); ArrayInfo cinfo = getInfo(rrT); float* pSrc0 = pinnedAlloc<float>(cinfo.elements()); float* pSrc1 = pinnedAlloc<float>(cinfo.elements()); float* pSrc2 = pinnedAlloc<float>(cinfo.elements()); AF_CHECK(af_get_data_ptr((void*)pSrc0, rrT)); AF_CHECK(af_get_data_ptr((void*)pSrc1, ggT)); AF_CHECK(af_get_data_ptr((void*)pSrc2, bbT)); // Copy the array into FreeImage buffer for (uint y = 0; y < fi_h; ++y) { for (uint x = 0; x < fi_w; ++x) { *(pDstLine + x * step + 2) = (uchar) pSrc0[indx]; // b *(pDstLine + x * step + 1) = (uchar) pSrc1[indx]; // g *(pDstLine + x * step + 0) = (uchar) pSrc2[indx]; // r ++indx; } pDstLine -= nDstPitch; } pinnedFree(pSrc0); pinnedFree(pSrc1); pinnedFree(pSrc2); } else { AF_CHECK(af_transpose(&rrT, rr, false)); ArrayInfo cinfo = getInfo(rrT); float* pSrc0 = pinnedAlloc<float>(cinfo.elements()); AF_CHECK(af_get_data_ptr((void*)pSrc0, rrT)); for (uint y = 0; y < fi_h; ++y) { for (uint x = 0; x < fi_w; ++x) { *(pDstLine + x * step) = (uchar) pSrc0[indx]; ++indx; } pDstLine -= nDstPitch; } pinnedFree(pSrc0); } FIMEMORY *stream = FreeImage_OpenMemory(); // now save the result image if (!(FreeImage_SaveToMemory(fif, pResultBitmap, stream, 0) == TRUE)) { AF_ERROR("FreeImage Error: Failed to save image", AF_ERR_RUNTIME); } *ptr = stream; FreeImage_Unload(pResultBitmap); if(free_in) AF_CHECK(af_release_array(in )); if(rr != 0) AF_CHECK(af_release_array(rr )); if(gg != 0) AF_CHECK(af_release_array(gg )); if(bb != 0) AF_CHECK(af_release_array(bb )); if(aa != 0) AF_CHECK(af_release_array(aa )); if(rrT!= 0) AF_CHECK(af_release_array(rrT)); if(ggT!= 0) AF_CHECK(af_release_array(ggT)); if(bbT!= 0) AF_CHECK(af_release_array(bbT)); if(aaT!= 0) AF_CHECK(af_release_array(aaT)); } CATCHALL return AF_SUCCESS; }
af_err af_assign_gen(af_array *out, const af_array lhs, const dim_t ndims, const af_index_t* indexs, const af_array rhs_) { af_array output = 0; af_array rhs = rhs_; // spanner is sequence index used for indexing along the // dimensions after ndims af_index_t spanner; spanner.idx.seq = af_span; spanner.isSeq = true; try { ARG_ASSERT(2, (ndims>0)); ARG_ASSERT(3, (indexs!=NULL)); int track = 0; vector<af_seq> seqs(4, af_span); for (dim_t i = 0; i < ndims; i++) { if (indexs[i].isSeq) { track++; seqs[i] = indexs[i].idx.seq; } } if (track==(int)ndims) { // all indexs are sequences, redirecting to af_assign return af_assign_seq(out, lhs, ndims, &(seqs.front()), rhs); } ARG_ASSERT(1, (lhs!=0)); ARG_ASSERT(4, (rhs!=0)); ArrayInfo lInfo = getInfo(lhs); ArrayInfo rInfo = getInfo(rhs); dim4 lhsDims = lInfo.dims(); dim4 rhsDims = rInfo.dims(); af_dtype lhsType= lInfo.getType(); af_dtype rhsType= rInfo.getType(); ARG_ASSERT(2, (ndims == 1) || (ndims == (dim_t)lInfo.ndims())); if (ndims == 1 && ndims != (dim_t)lInfo.ndims()) { af_array tmp_in = 0, tmp_out = 0; AF_CHECK(af_flat(&tmp_in, lhs)); AF_CHECK(af_assign_gen(&tmp_out, tmp_in, ndims, indexs, rhs_)); AF_CHECK(af_moddims(out, tmp_out, lInfo.ndims(), lInfo.dims().get())); AF_CHECK(af_release_array(tmp_in)); AF_CHECK(af_release_array(tmp_out)); return AF_SUCCESS; } ARG_ASSERT(1, (lhsType==rhsType)); ARG_ASSERT(3, (rhsDims.ndims()>0)); ARG_ASSERT(1, (lhsDims.ndims()>=rhsDims.ndims())); ARG_ASSERT(2, (lhsDims.ndims()>=ndims)); if (*out != lhs) { int count = 0; AF_CHECK(af_get_data_ref_count(&count, lhs)); if (count > 1) { AF_CHECK(af_copy_array(&output, lhs)); } else { AF_CHECK(af_retain_array(&output, lhs)); } } else { output = lhs; } dim4 oDims = toDims(seqs, lhsDims); // if af_array are indexs along any // particular dimension, set the length of // that dimension accordingly before any checks for (dim_t i=0; i<ndims; i++) { if (!indexs[i].isSeq) { oDims[i] = getInfo(indexs[i].idx.arr).elements(); } } for (dim_t i = ndims; i < (dim_t)lInfo.ndims(); i++) { oDims[i] = 1; } bool is_vector = true; for (int i = 0; is_vector && i < oDims.ndims() - 1; i++) { is_vector &= oDims[i] == 1; } //TODO: Move logic out of this is_vector &= rInfo.isVector() || rInfo.isScalar(); if (is_vector) { if (oDims.elements() != (dim_t)rInfo.elements() && rInfo.elements() != 1) { AF_ERROR("Size mismatch between input and output", AF_ERR_SIZE); } if (rInfo.elements() == 1) { AF_CHECK(af_tile(&rhs, rhs_, oDims[0], oDims[1], oDims[2], oDims[3])); } else { // If both out and rhs are vectors of equal elements, reshape rhs to out dims AF_CHECK(af_moddims(&rhs, rhs_, oDims.ndims(), oDims.get())); } } else { for (int i = 0; i < 4; i++) { if (oDims[i] != rhsDims[i]) { AF_ERROR("Size mismatch between input and output", AF_ERR_SIZE); } } } af_index_t idxrs[4]; // set all dimensions above ndims to spanner index for (dim_t i=ndims; i<4; ++i) idxrs[i] = spanner; for (dim_t i=0; i<ndims; ++i) { if (!indexs[i].isSeq) { // check if all af_arrays have atleast one value // to enable indexing along that dimension ArrayInfo idxInfo = getInfo(indexs[i].idx.arr); af_dtype idxType = idxInfo.getType(); ARG_ASSERT(3, (idxType!=c32)); ARG_ASSERT(3, (idxType!=c64)); ARG_ASSERT(3, (idxType!=b8 )); idxrs[i].idx.arr = indexs[i].idx.arr; idxrs[i].isSeq = indexs[i].isSeq; } else { // af_seq is being used for this dimension // just copy the index to local variable idxrs[i] = indexs[i]; } } try { switch(rhsType) { case c64: genAssign<cdouble>(output, idxrs, rhs); break; case f64: genAssign<double >(output, idxrs, rhs); break; case c32: genAssign<cfloat >(output, idxrs, rhs); break; case f32: genAssign<float >(output, idxrs, rhs); break; case u64: genAssign<uintl >(output, idxrs, rhs); break; case u32: genAssign<uint >(output, idxrs, rhs); break; case s64: genAssign<intl >(output, idxrs, rhs); break; case s32: genAssign<int >(output, idxrs, rhs); break; case u8: genAssign<uchar >(output, idxrs, rhs); break; case b8: genAssign<char >(output, idxrs, rhs); break; default: TYPE_ERROR(1, rhsType); } } catch(...) { if (*out != lhs) { AF_CHECK(af_release_array(output)); if (is_vector) { AF_CHECK(af_release_array(rhs)); } } throw; } if (is_vector) { AF_CHECK(af_release_array(rhs)); } } CATCHALL; std::swap(*out, output); return AF_SUCCESS; }
af_err af_assign_seq(af_array *out, const af_array lhs, const unsigned ndims, const af_seq *index, const af_array rhs) { try { ARG_ASSERT(0, (lhs!=0)); ARG_ASSERT(1, (ndims>0)); ARG_ASSERT(3, (rhs!=0)); ArrayInfo lInfo = getInfo(lhs); if (ndims == 1 && ndims != (dim_t)lInfo.ndims()) { af_array tmp_in, tmp_out; AF_CHECK(af_flat(&tmp_in, lhs)); AF_CHECK(af_assign_seq(&tmp_out, tmp_in, ndims, index, rhs)); AF_CHECK(af_moddims(out, tmp_out, lInfo.ndims(), lInfo.dims().get())); AF_CHECK(af_release_array(tmp_in)); AF_CHECK(af_release_array(tmp_out)); return AF_SUCCESS; } for(dim_t i=0; i<(dim_t)ndims; ++i) { ARG_ASSERT(2, (index[i].step>=0)); } af_array res = 0; if (*out != lhs) { int count = 0; AF_CHECK(af_get_data_ref_count(&count, lhs)); if (count > 1) { AF_CHECK(af_copy_array(&res, lhs)); } else { AF_CHECK(af_retain_array(&res, lhs)); } } else { res = lhs; } try { if (lhs != rhs) { ArrayInfo oInfo = getInfo(lhs); af_dtype oType = oInfo.getType(); switch(oType) { case c64: assign_helper<cdouble>(getWritableArray<cdouble>(res), ndims, index, rhs); break; case c32: assign_helper<cfloat >(getWritableArray<cfloat >(res), ndims, index, rhs); break; case f64: assign_helper<double >(getWritableArray<double >(res), ndims, index, rhs); break; case f32: assign_helper<float >(getWritableArray<float >(res), ndims, index, rhs); break; case s32: assign_helper<int >(getWritableArray<int >(res), ndims, index, rhs); break; case u32: assign_helper<uint >(getWritableArray<uint >(res), ndims, index, rhs); break; case s64: assign_helper<intl >(getWritableArray<intl >(res), ndims, index, rhs); break; case u64: assign_helper<uintl >(getWritableArray<uintl >(res), ndims, index, rhs); break; case u8 : assign_helper<uchar >(getWritableArray<uchar >(res), ndims, index, rhs); break; case b8 : assign_helper<char >(getWritableArray<char >(res), ndims, index, rhs); break; default : TYPE_ERROR(1, oType); break; } } } catch(...) { af_release_array(res); throw; } std::swap(*out, res); } CATCHALL; return AF_SUCCESS; }