def data(self, data): data = self._preprocess_data(data) if isinstance(data, dict): labeled_by = data.pop('labeled_by', 'rows') data_contiguous = data.pop('contiguous', None) if data_contiguous is not None: self.data = data_contiguous if len(data) == 0: return if labeled_by not in ('rows', 'columns'): raise ValueError( 'when data provided as a dictionary of ' 'matrices, the optional dictionary entry ' '`labeled_by` must be one of `columns` or `rows` ' '(default)') if not all(sparse_or_dense(m) for m in data.values()): raise TypeError('when data provided as a dictionary of ' 'matrices, each value must be one of the ' 'following matrix types: {}' ''.format(CONRAD_MATRIX_TYPES)) if labeled_by == 'columns': for mat in data.values(): rows = mat.shape[0] break if not all([m.shape[0] == rows for m in data.values()]): raise ValueError('all submatrices must have consistent ' 'number of rows when a dictionary of ' 'horizontally concatenable matrices is ' 'provided') columns = sum([m.shape[1] for m in data.values()]) else: rows = sum([m.shape[0] for m in data.values()]) for mat in data.values(): columns = mat.shape[1] break if not all([m.shape[1] == columns for m in data.values()]): raise ValueError('all submatrices must have consistent ' 'number of columns when a dictionary of ' 'vertically concatenable matrices is ' 'provided') self.__shape_check((rows, columns)) self.__dim1, self.__dim2 = rows, columns if labeled_by == 'columns': self.__column_slices.update(data) else: self.__row_slices.update(data) else: if not sparse_or_dense(data): raise TypeError('when data provided as a singleton matrix, ' 'it must be formatted as one of the following ' 'matrix types {}'.format(CONRAD_MATRIX_TYPES)) self.__shape_check(data.shape) self.__dim1, self.__dim2 = data.shape self.__data = data
def frame0_to_1(self, in_): """ Allocating version of :meth`AbstractMapping.frame1_to_0`. If input array is a matrix, mapping operates on rows. If array is a vector, mapping operates on entries. Arguments: in_: Input array with :attr:`AbstractMapping.n_frame0` rows and ``k`` >= ``1`` columns. Returns: :class:`numpy.ndarray`: Array with :attr:`AbstractMapping.n_frame0` rows and same number of columns as input. Input entries are mapped one-to-one or many-to-one *into* output. """ if is_vector(in_): out_ = zeros(self.__n_frame0) elif sparse_or_dense(in_): dim1 = self.__n_frame0 dim2 = in_.shape[1] out_ = zeros((dim1, dim2)) return self.frame1_to_0_inplace(in_, out_)
def frame0_to_1(self, in_): """ Map elements of array ``in_`` to a new array. If input array is a matrix, mapping operates on rows. If array is a vector, mapping operates on entries. A new empty vector or matrix Arguments: in_: Input array with :attr:`AbstractMapping.n_frame0` rows and ``k`` >= ``1`` columns. Returns: :class:`numpy.ndarray`: Array with :attr:`AbstractMapping.n_frame1` rows and ``k`` columns. Input entries are mapped one-to-one or one-to-many *into* output. """ if is_vector(in_): out_ = zeros(self.__n_frame1) elif sparse_or_dense(in_): dim1 = self.__n_frame1 dim2 = in_.shape[1] out_ = zeros((dim1, dim2)) return self.frame0_to_1_inplace(in_, out_)
def to_unsafe_data(self, unsafe_file_entry): if isinstance(unsafe_file_entry, dict): unsafe_file_entry = UnsafeFileEntry(**unsafe_file_entry) if not isinstance(unsafe_file_entry, UnsafeFileEntry): raise TypeError('input should be of type (or parsable as) {}' ''.format(UnsafeFileEntry)) if not unsafe_file_entry.complete: raise ValueError( 'no numpy file assigned to {}'.format(UnsafeFileEntry)) typed_data = self.read_all(unsafe_file_entry.file) if isinstance(typed_data, np.ndarray): return typed_data if sparse_or_dense(typed_data): return typed_data if isinstance(typed_data, dict): sme = SparseMatrixEntry(**typed_data) if sme.complete: return self.to_sparse_matrix(sme) dme = DenseMatrixEntry(**typed_data) if dme.complete: return self.to_dense_matrix(dme) ve = VectorEntry(**typed_data) if ve.complete: return self.to_vector(ve) return typed_data
def A_mean(self, A_mean=None): if A_mean is not None: if not isinstance(A_mean, np.ndarray): raise TypeError('if argument "A_mean" is provided, it must be ' 'of type {}'.format(np.ndarray)) elif not A_mean.size in A_mean.shape: raise ValueError( 'if argument "A_mean" is provided, it must be ' 'a row or column vector. shape of argument: {}' ''.format(A_mean.shape)) else: if self.__A_full is not None: if len(A_mean) != self.__A_full.shape[1]: raise ValueError( 'field "A_full" already set; proposed ' 'value for "A_mean" must have same ' 'number of entries ({}) as columns in ' 'A_full ({})'.format(len(A_mean), self.__A_full.shape[1])) self.__A_mean = vec(A_mean) elif self.__A_full is not None: if not sparse_or_dense(self.A_full): raise TypeError('cannot calculate structure.A_mean from' 'structure.A_full: A_full must be one of ' '({},{},{})'.format(np.ndarray, sp.csc_matrix, sp.csr_matrix)) else: if isinstance(self.A_full, np.ndarray): self.__A_mean = np.dot(self.voxel_weights, self.A_full) else: self.__A_mean = vec(self.voxel_weights * self.A_full) self.__A_mean /= float(self.weighted_size)
def A_mean(self, A_mean=None): if A_mean is not None: if not isinstance(A_mean, ndarray): raise TypeError('if argument "A_mean" is provided, it ' 'must be of type {}'.format(ndarray)) elif not A_mean.size in A_mean.shape: raise ValueError('if argument "A_mean" is provided, it must be' ' a row or column vector. shape of argument: ' '{}'.format(A_mean.shape)) else: if self.__A_full is not None: if len(A_mean) != self.__A_full.shape[1]: raise ValueError('field "A_full" already set; ' 'proposed value for "A_mean" ' 'must have same number of entries ' '({}) as columns in A_full ({})' ''.format(len(A_mean), self.__A_full.shape[1])) self.__A_mean = vec(A_mean) elif self.__A_full is not None: if not sparse_or_dense(self.A_full): raise TypeError('cannot calculate structure.A_mean from' 'structure.A_full: A_full must be one of' ' ({},{},{})'.format(ndarray, csc_matrix, csr_matrix)) else: self.__A_mean = self.A_full.sum(0) / self.A_full.shape[0] if not isinstance(self.A_full, ndarray): self.__A_mean = vec(self.__A_mean)
def frame1_to_0(self, in_): """ Allocating version of :meth`DiscreteMapping.frame1_to_0`. If input array is a matrix, mapping operates on rows. If array is a vector, mapping operates on entries. Arguments: in_: Input array with :attr:`DiscreteMapping.n_frame0` rows and ``k`` >= ``1`` columns. Returns: :class:`numpy.ndarray`: Array with :attr:`DiscreteMapping.n_frame0` rows and same number of columns as input. Input entries are mapped one-to-one or many-to-one *into* output. """ if is_vector(in_): out_ = np.zeros(self.__n_frame0) elif sparse_or_dense(in_): dim1 = self.__n_frame0 dim2 = in_.shape[1] out_ = np.zeros((dim1, dim2)) return self.frame1_to_0_inplace(in_, out_)
def frame0_to_1(self, in_): """ Map elements of array ``in_`` to a new array. If input array is a matrix, mapping operates on rows. If array is a vector, mapping operates on entries. A new empty vector or matrix Arguments: in_: Input array with :attr:`DiscreteMapping.n_frame0` rows and ``k`` >= ``1`` columns. Returns: :class:`numpy.ndarray`: Array with :attr:`DiscreteMapping.n_frame1` rows and ``k`` columns. Input entries are mapped one-to-one or one-to-many *into* output. """ if is_vector(in_): out_ = np.zeros(self.__n_frame1) elif sparse_or_dense(in_): dim1 = self.__n_frame1 dim2 = in_.shape[1] out_ = np.zeros((dim1, dim2)) return self.frame0_to_1_inplace(in_, out_)
def write_matrix(self, directory, name, matrix, overwrite=False): if not sparse_or_dense(matrix): raise TypeError('matrix to save must be one of {}' ''.format(CONRAD_MATRIX_TYPES)) if isinstance(matrix, np.ndarray): return self.write_dense_matrix(directory, name, matrix, overwrite) else: return self.write_sparse_matrix(directory, name, matrix, overwrite)
def plannable(self): """ True if structure's attached data is sufficient for optimization. Minimum requirements: - Structure size determined, and - Dose matrix assigned, *or* - Structure collapsable and mean dose matrix assigned. """ size_determined = positive_real_valued(self.size) full_mat_usable = sparse_or_dense(self.A_full) if full_mat_usable: full_mat_usable &= self.size == self.A_full.shape[0] collapsed_mat_usable = bool( isinstance(self.A_mean, np.ndarray) and self.collapsable) usable_matrix_loaded = full_mat_usable or collapsed_mat_usable return size_determined and usable_matrix_loaded
def plannable(self): """ True if structure's attached data is sufficient for optimization. Minimum requirements: - Structure size determined, and - Dose matrix assigned, *or* - Structure collapsable and mean dose matrix assigned. """ size_set = positive_real_valued(self.size) full_mat_usable = sparse_or_dense(self.A_full) if full_mat_usable: full_mat_usable &= self.size == self.A_full.shape[0] collapsed_mat_usable = bool( isinstance(self.A_mean, ndarray) and self.collapsable) usable_matrix_loaded = full_mat_usable or collapsed_mat_usable return size_set and usable_matrix_loaded
def A_full(self, A_full): if A_full is None: return # verify type of A_full if not sparse_or_dense(A_full): raise TypeError('input A must by a numpy or scipy csr/csc ' 'sparse matrix') if self.size is not None: if A_full.shape[0] != self.size: raise ValueError('# rows of "A_full" must correspond to ' 'value of property size ({}) of {} ' 'object'.format(self.size, Structure)) else: self.size = A_full.shape[0] self.__A_full = A_full # Pass "None" to self.A_mean setter to trigger calculation of # mean dose matrix from full dose matrix. self.A_mean = None
def frame0_to_1_inplace(self, in_, out_, clear_output=False): """ Map elements of array ``in_`` to elements of array ``out_``. Procedure:: # let forward_map be the map: SET_0 --> SET_1. # for each INDEX_0, INDEX_1 in forward_map, do # out_[INDEX_1] += in_[INDEX_0] # end for If arrays are matrices, mapping operates on rows. If arrays are vectors, mapping operates on entries. Arguments: in_: Input array with :attr:`AbstractMapping.n_frame0` rows and ``k`` >= ``1`` columns. out_: Output array with :attr:`AbstractMapping.n_frame1` rows and ``k`` >= 1 columns. Modified in-place. clear_output (:obj:`bool`, optional): If ``True``, set output array to ``0`` before adding input values. Returns: Vector `out_`, after in-place modification. Raises: TypeError: If input and output arrays are not (jointly) vectors or matrices. ValueError: If input and output array dimensions are not compatible with each other or consistent with the dimensions of the mapping. """ vector_processing = is_vector(in_) and is_vector(out_) matrix_processing = sparse_or_dense(in_) and sparse_or_dense(out_) if not vector_processing or matrix_processing: raise TypeError('arguments "in_" and "out_" be numpy or ' 'scipy vectors or matrices') dim_in1 = in_.shape[0] dim_out1 = out_.shape[0] if vector_processing: dim_in2 = 1 dim_out2 = 1 else: dim_in2 = in_.shape[1] dim_out2 = out_.shape[1] if bool( dim_in_1 != self.n_frame0 or dim_out1 != self.n_frame1 or dim_in2 != dim_out2): raise ValueError('arguments "in_" and "out_" be vectors or ' 'matrices of dimensions M x N, and K x N, ' 'respectively, with:\nM = {}\nK={}\n' 'Provided:\n input: {}x{}\noutput: {}x{}' ''.format(self.n_frame0, self.n_frame1, dim_in1, dim_in2, dim_out1, dim_out2)) if clear_output: out_ *= 0 if vector_processing: for idx_0, idx_1 in enumerate(self.vec): out_[idx_1] += in_[idx_0] if matrix_processing: for idx_0, idx_1 in enumerate(self.vec): out_[idx_1, :] += in_[idx_0, :] return out_
def frame0_to_1_inplace(self, in_, out_, clear_output=False): """ Map elements of array ``in_`` to elements of array ``out_``. Procedure:: # let forward_map be the map: SET_0 --> SET_1. # for each INDEX_0, INDEX_1 in forward_map, do # out_[INDEX_1] += in_[INDEX_0] # end for If arrays are matrices, mapping operates on rows. If arrays are vectors, mapping operates on entries. Arguments: in_: Input array with :attr:`DiscreteMapping.n_frame0` rows and ``k`` >= ``1`` columns. out_: Output array with :attr:`DiscreteMapping.n_frame1` rows and ``k`` >= 1 columns. Modified in-place. clear_output (:obj:`bool`, optional): If ``True``, set output array to ``0`` before adding input values. Returns: Vector `out_`, after in-place modification. Raises: TypeError: If input and output arrays are not (jointly) vectors or matrices. ValueError: If input and output array dimensions are not compatible with each other or consistent with the dimensions of the mapping. """ vector_processing = is_vector(in_) and is_vector(out_) matrix_processing = sparse_or_dense(in_) and sparse_or_dense(out_) if not (vector_processing or matrix_processing): raise TypeError('arguments "in_" and "out_" be numpy or ' 'scipy vectors or matrices') dim_in1 = in_.shape[0] dim_out1 = out_.shape[0] if vector_processing: dim_in2 = 1 dim_out2 = 1 else: dim_in2 = in_.shape[1] dim_out2 = out_.shape[1] if bool( dim_in1 != self.n_frame0 or dim_out1 != self.n_frame1 or dim_in2 != dim_out2): raise ValueError('arguments "in_" and "out_" be vectors or ' 'matrices of dimensions M x N, and K x N, ' 'respectively, with:\nM = {}\nK={}\n' 'Provided:\n input: {}x{}\noutput: {}x{}' ''.format(self.n_frame0, self.n_frame1, dim_in1, dim_in2, dim_out1, dim_out2)) if clear_output: out_ *= 0 if vector_processing: for idx_0, idx_1 in enumerate(self.vec): out_[idx_1] += in_[idx_0] else: for idx_0, idx_1 in enumerate(self.vec): out_[idx_1, :] += in_[idx_0, :] # TODO: use efficient slicing when input is sparse. warn when output sparse?? return out_