nd::array nd::view(const nd::array& arr, const ndt::type& tp) { // If the types match exactly, simply return 'arr' if (arr.get_type() == tp) { return arr; } else if (arr.get_ndim() == tp.get_ndim()) { // Allocate a result array to attempt the view in it array result(make_array_memory_block(tp.get_metadata_size())); // Copy the fields result.get_ndo()->m_data_pointer = arr.get_ndo()->m_data_pointer; if (arr.get_ndo()->m_data_reference == NULL) { // Embedded data, need reference to the array result.get_ndo()->m_data_reference = arr.get_memblock().release(); } else { // Use the same data reference, avoid producing a chain result.get_ndo()->m_data_reference = arr.get_data_memblock().release(); } result.get_ndo()->m_type = ndt::type(tp).release(); result.get_ndo()->m_flags = arr.get_ndo()->m_flags; // Now try to copy the metadata as a view if (try_view(arr.get_type(), arr.get_ndo_meta(), tp, result.get_ndo_meta(), arr.get_memblock().get())) { // If it succeeded, return it return result; } // Otherwise fall through, let it get destructed, and raise an error } stringstream ss; ss << "Unable to view nd::array of type " << arr.get_type(); ss << "as type " << tp; throw type_error(ss.str()); }
static nd::array view_concrete(const nd::array &arr, const ndt::type &tp) { // Allocate a result array to attempt the view in it nd::array result(make_array_memory_block(tp.get_arrmeta_size())); // Copy the fields result.get_ndo()->data.ptr = arr.get_ndo()->data.ptr; if (arr.get_ndo()->data.ref == NULL) { // Embedded data, need reference to the array result.get_ndo()->data.ref = arr.get_memblock().release(); } else { // Use the same data reference, avoid producing a chain result.get_ndo()->data.ref = arr.get_data_memblock().release(); } result.get_ndo()->m_type = ndt::type(tp).release(); result.get_ndo()->m_flags = arr.get_ndo()->m_flags; // First handle a special case of viewing outermost "var" as "fixed[#]" if (arr.get_type().get_type_id() == var_dim_type_id && tp.get_type_id() == fixed_dim_type_id) { const var_dim_type_arrmeta *in_am = reinterpret_cast<const var_dim_type_arrmeta *>(arr.get_arrmeta()); const var_dim_type_data *in_dat = reinterpret_cast<const var_dim_type_data *>(arr.get_readonly_originptr()); fixed_dim_type_arrmeta *out_am = reinterpret_cast<fixed_dim_type_arrmeta *>(result.get_arrmeta()); out_am->dim_size = tp.extended<ndt::fixed_dim_type>()->get_fixed_dim_size(); out_am->stride = in_am->stride; if ((intptr_t)in_dat->size == out_am->dim_size) { // Use the more specific data reference from the var arrmeta if possible if (in_am->blockref != NULL) { memory_block_decref(result.get_ndo()->data.ref); memory_block_incref(in_am->blockref); result.get_ndo()->data.ref = in_am->blockref; } result.get_ndo()->data.ptr = in_dat->begin + in_am->offset; // Try to copy the rest of the arrmeta as a view if (try_view(arr.get_type().extended<ndt::base_dim_type>()->get_element_type(), arr.get_arrmeta() + sizeof(var_dim_type_arrmeta), tp.extended<ndt::base_dim_type>()->get_element_type(), result.get_arrmeta() + sizeof(fixed_dim_type_arrmeta), arr.get_memblock().get())) { return result; } } } // Otherwise try to copy the arrmeta as a view else if (try_view(arr.get_type(), arr.get_arrmeta(), tp, result.get_arrmeta(), arr.get_memblock().get())) { // If it succeeded, return it return result; } stringstream ss; ss << "Unable to view nd::array of type " << arr.get_type(); ss << " as type " << tp; throw type_error(ss.str()); }
static nd::array array_function_dereference(const nd::array &self) { // Follow the pointers to eliminate them ndt::type dt = self.get_type(); const char *arrmeta = self.get_arrmeta(); char *data = self.get_ndo()->m_data_pointer; memory_block_data *dataref = self.get_ndo()->m_data_reference; if (dataref == NULL) { dataref = self.get_memblock().get(); } uint64_t flags = self.get_ndo()->m_flags; while (dt.get_type_id() == pointer_type_id) { const pointer_type_arrmeta *md = reinterpret_cast<const pointer_type_arrmeta *>(arrmeta); dt = dt.extended<ndt::pointer_type>()->get_target_type(); arrmeta += sizeof(pointer_type_arrmeta); data = *reinterpret_cast<char **>(data) + md->offset; dataref = md->blockref; } // Create an array without the pointers nd::array result(make_array_memory_block(dt.get_arrmeta_size())); if (!dt.is_builtin()) { dt.extended()->arrmeta_copy_construct(result.get_arrmeta(), arrmeta, &self.get_ndo()->m_memblockdata); } result.get_ndo()->m_type = dt.release(); result.get_ndo()->m_data_pointer = data; result.get_ndo()->m_data_reference = dataref; memory_block_incref(result.get_ndo()->m_data_reference); result.get_ndo()->m_flags = flags; return result; }
/** * Adds a ckernel layer for processing one dimension of the reduction. * This is for a strided dimension which is being broadcast, and is * the final dimension before the accumulation operation. */ static size_t make_strided_inner_broadcast_dimension_kernel( const callable_type_data *elwise_reduction_const, const ndt::callable_type *elwise_reduction_tp, const callable_type_data *dst_initialization_const, const ndt::callable_type *dst_initialization_tp, void *ckb, intptr_t ckb_offset, intptr_t dst_stride, intptr_t src_stride, intptr_t src_size, const ndt::type &dst_tp, const char *dst_arrmeta, const ndt::type &src_tp, const char *src_arrmeta, bool right_associative, const nd::array &reduction_identity, kernel_request_t kernreq, const eval::eval_context *ectx) { callable_type_data *elwise_reduction = const_cast<callable_type_data *>(elwise_reduction_const); callable_type_data *dst_initialization = const_cast<callable_type_data *>(dst_initialization_const); intptr_t root_ckb_offset = ckb_offset; strided_inner_broadcast_kernel_extra *e = reinterpret_cast<ckernel_builder<kernel_request_host> *>(ckb) ->alloc_ck<strided_inner_broadcast_kernel_extra>(ckb_offset); e->destructor = &strided_inner_broadcast_kernel_extra::destruct; // Cannot have both a dst_initialization kernel and a reduction identity if (dst_initialization != NULL && !reduction_identity.is_null()) { throw invalid_argument( "make_lifted_reduction_ckernel: cannot specify" " both a dst_initialization kernel and a reduction_identity"); } if (reduction_identity.is_null()) { // Get the function pointer for the first_call, for the case with // no reduction identity if (kernreq == kernel_request_single) { e->set_first_call_function( &strided_inner_broadcast_kernel_extra::single_first); } else if (kernreq == kernel_request_strided) { e->set_first_call_function( &strided_inner_broadcast_kernel_extra::strided_first); } else { stringstream ss; ss << "make_lifted_reduction_ckernel: unrecognized request " << (int)kernreq; throw runtime_error(ss.str()); } } else { // Get the function pointer for the first_call, for the case with // a reduction identity if (kernreq == kernel_request_single) { e->set_first_call_function( &strided_inner_broadcast_kernel_extra::single_first_with_ident); } else if (kernreq == kernel_request_strided) { e->set_first_call_function( &strided_inner_broadcast_kernel_extra::strided_first_with_ident); } else { stringstream ss; ss << "make_lifted_reduction_ckernel: unrecognized request " << (int)kernreq; throw runtime_error(ss.str()); } if (reduction_identity.get_type() != dst_tp) { stringstream ss; ss << "make_lifted_reduction_ckernel: reduction identity type "; ss << reduction_identity.get_type() << " does not match dst type "; ss << dst_tp; throw runtime_error(ss.str()); } e->ident_data = reduction_identity.get_readonly_originptr(); e->ident_ref = reduction_identity.get_memblock().release(); } // The function pointer for followup accumulation calls e->set_followup_call_function( &strided_inner_broadcast_kernel_extra::strided_followup); // The striding parameters e->dst_stride = dst_stride; e->src_stride = src_stride; e->size = src_size; // Validate that the provided callables are unary operations, // and have the correct types if (elwise_reduction_tp->get_npos() != 1 && elwise_reduction_tp->get_npos() != 2) { stringstream ss; ss << "make_lifted_reduction_ckernel: elwise reduction ckernel "; ss << "funcproto must be unary or a binary expr with all equal types"; throw runtime_error(ss.str()); } if (elwise_reduction_tp->get_return_type() != dst_tp) { stringstream ss; ss << "make_lifted_reduction_ckernel: elwise reduction ckernel "; ss << "dst type is " << elwise_reduction_tp->get_return_type(); ss << ", expected " << dst_tp; throw type_error(ss.str()); } if (elwise_reduction_tp->get_pos_type(0) != src_tp) { stringstream ss; ss << "make_lifted_reduction_ckernel: elwise reduction ckernel "; ss << "src type is " << elwise_reduction_tp->get_return_type(); ss << ", expected " << src_tp; throw type_error(ss.str()); } if (dst_initialization != NULL) { check_dst_initialization(dst_initialization_tp, dst_tp, src_tp); } if (elwise_reduction_tp->get_npos() == 2) { ckb_offset = kernels::wrap_binary_as_unary_reduction_ckernel( ckb, ckb_offset, right_associative, kernel_request_strided); ndt::type src_tp_doubled[2] = {src_tp, src_tp}; const char *src_arrmeta_doubled[2] = {src_arrmeta, src_arrmeta}; ckb_offset = elwise_reduction->instantiate( elwise_reduction->static_data, 0, NULL, ckb, ckb_offset, dst_tp, dst_arrmeta, elwise_reduction_tp->get_npos(), src_tp_doubled, src_arrmeta_doubled, kernel_request_strided, ectx, nd::array(), std::map<nd::string, ndt::type>()); } else { ckb_offset = elwise_reduction->instantiate( elwise_reduction->static_data, 0, NULL, ckb, ckb_offset, dst_tp, dst_arrmeta, elwise_reduction_tp->get_npos(), &src_tp, &src_arrmeta, kernel_request_strided, ectx, nd::array(), std::map<nd::string, ndt::type>()); } // Make sure there's capacity for the next ckernel reinterpret_cast<ckernel_builder<kernel_request_host> *>(ckb) ->reserve(ckb_offset + sizeof(ckernel_prefix)); // Need to retrieve 'e' again because it may have moved e = reinterpret_cast<ckernel_builder<kernel_request_host> *>(ckb) ->get_at<strided_inner_broadcast_kernel_extra>(root_ckb_offset); e->dst_init_kernel_offset = ckb_offset - root_ckb_offset; if (dst_initialization != NULL) { ckb_offset = dst_initialization->instantiate( dst_initialization->static_data, 0, NULL, ckb, ckb_offset, dst_tp, dst_arrmeta, elwise_reduction_tp->get_npos(), &src_tp, &src_arrmeta, kernel_request_strided, ectx, nd::array(), std::map<nd::string, ndt::type>()); } else if (reduction_identity.is_null()) { ckb_offset = make_assignment_kernel(ckb, ckb_offset, dst_tp, dst_arrmeta, src_tp, src_arrmeta, kernel_request_strided, ectx); } else { ckb_offset = make_assignment_kernel( ckb, ckb_offset, dst_tp, dst_arrmeta, reduction_identity.get_type(), reduction_identity.get_arrmeta(), kernel_request_strided, ectx); } return ckb_offset; }
dynd::nd::array pydynd::nd_fields(const nd::array& n, PyObject *field_list) { vector<string> selected_fields; pyobject_as_vector_string(field_list, selected_fields); // TODO: Move this implementation into dynd ndt::type fdt = n.get_dtype(); if (fdt.get_kind() != struct_kind) { stringstream ss; ss << "nd.fields must be given a dynd array of 'struct' kind, not "; ss << fdt; throw runtime_error(ss.str()); } const base_struct_type *bsd = static_cast<const base_struct_type *>(fdt.extended()); const ndt::type *field_types = bsd->get_field_types(); if (selected_fields.empty()) { throw runtime_error("nd.fields requires at least one field name to be specified"); } // Construct the field mapping and output field types vector<intptr_t> selected_index(selected_fields.size()); vector<ndt::type> selected_ndt_types(selected_fields.size()); for (size_t i = 0; i != selected_fields.size(); ++i) { selected_index[i] = bsd->get_field_index(selected_fields[i]); if (selected_index[i] < 0) { stringstream ss; ss << "field name "; print_escaped_utf8_string(ss, selected_fields[i]); ss << " does not exist in dynd type " << fdt; throw runtime_error(ss.str()); } selected_ndt_types[i] = field_types[selected_index[i]]; } // Create the result udt ndt::type rudt = ndt::make_struct(selected_ndt_types, selected_fields); ndt::type result_tp = n.get_type().with_replaced_dtype(rudt); const base_struct_type *rudt_bsd = static_cast<const base_struct_type *>(rudt.extended()); // Allocate the new memory block. size_t metadata_size = result_tp.get_metadata_size(); nd::array result(make_array_memory_block(metadata_size)); // Clone the data pointer result.get_ndo()->m_data_pointer = n.get_ndo()->m_data_pointer; result.get_ndo()->m_data_reference = n.get_ndo()->m_data_reference; if (result.get_ndo()->m_data_reference == NULL) { result.get_ndo()->m_data_reference = n.get_memblock().get(); } memory_block_incref(result.get_ndo()->m_data_reference); // Copy the flags result.get_ndo()->m_flags = n.get_ndo()->m_flags; // Set the type and transform the metadata result.get_ndo()->m_type = ndt::type(result_tp).release(); // First copy all the array data type metadata ndt::type tmp_dt = result_tp; char *dst_metadata = result.get_ndo_meta(); const char *src_metadata = n.get_ndo_meta(); while (tmp_dt.get_ndim() > 0) { if (tmp_dt.get_kind() != uniform_dim_kind) { throw runtime_error("nd.fields doesn't support dimensions with pointers yet"); } const base_uniform_dim_type *budd = static_cast<const base_uniform_dim_type *>( tmp_dt.extended()); size_t offset = budd->metadata_copy_construct_onedim(dst_metadata, src_metadata, n.get_memblock().get()); dst_metadata += offset; src_metadata += offset; tmp_dt = budd->get_element_type(); } // Then create the metadata for the new struct const size_t *metadata_offsets = bsd->get_metadata_offsets(); const size_t *result_metadata_offsets = rudt_bsd->get_metadata_offsets(); const size_t *data_offsets = bsd->get_data_offsets(src_metadata); size_t *result_data_offsets = reinterpret_cast<size_t *>(dst_metadata); for (size_t i = 0; i != selected_fields.size(); ++i) { const ndt::type& dt = selected_ndt_types[i]; // Copy the data offset result_data_offsets[i] = data_offsets[selected_index[i]]; // Copy the metadata for this field if (dt.get_metadata_size() > 0) { dt.extended()->metadata_copy_construct(dst_metadata + result_metadata_offsets[i], src_metadata + metadata_offsets[selected_index[i]], n.get_memblock().get()); } } return result; }