def test_structure_creation(self): # Test that the appropriate dictionary containing ArrayStructures is # computed when constructing a GroupStructure from_component_arrays. array = np.arange(6) expected_structure = {'a': ArrayStructure.from_array(array)} grp = GroupStructure.from_component_arrays({'a': array}) self.assertEqual(grp.length, 6) self.assertEqual(grp._cmpt_structure, expected_structure)
def optimal_array_structure(ordering_elements, actual_values_elements=None): """ Calculate an optimal array replication structure for a set of vectors. Args: * ordering_elements (iterable of (name, 1-d array)): Input element names and value-vectors. Must all be the same length (but not necessarily type). Must have at least one. Kwargs: * actual_values_elements (iterable of (name, 1-d array)): The 'real' values used to construct the result arrays, if different from 'ordering_elements'. Must contain all the same names (but not necessarily in the same order). The 'ordering_elements' arg contains the pattern used to deduce a structure. The order of this is significant, in that earlier elements get priority when associating dimensions with specific elements. Returns: dims_shape, primary_elements, element_arrays_and_dims, where: * 'dims_shape' is the shape of the vector dimensions chosen. * 'primary_elements' is a set of dimension names; the names of input elements that are identified as dimensions. At most one for each dimension. * 'element_arrays_and_dims' is a dictionary [name: (array, dims)], for all elements that are not dimensionless. Each array is reduced to the shape of its mapped dimension. For example:: >>> import iris.fileformats.um._optimal_array_structuring as optdims >>> elements_structure = [('a', np.array([1, 1, 1, 2, 2, 2])), ... ('b', np.array([0, 1, 2, 0, 1, 2])), ... ('c', np.array([11, 12, 13, 14, 15, 16]))] >>> elements_values = [('a', np.array([10, 10, 10, 12, 12, 12])), ... ('b', np.array([15, 16, 17, 15, 16, 17])), ... ('c', np.array([9, 3, 5, 2, 7, 1]))] >>> dims_shape, dim_names, arrays_and_dims = \ ... optdims.optimal_array_structure(elements_structure, ... elements_values) >>> print dims_shape (2, 3) >>> print dim_names set(['a', 'b']) >>> print arrays_and_dims {'a': (array([10, 12]), (0,)), 'c': (array([[9, 3, 5], [2, 7, 1]]), (0, 1)), 'b': (array([15, 16, 17]), (1,))} """ # Convert the inputs to dicts. element_ordering_arrays = dict(ordering_elements) if actual_values_elements is None: actual_values_elements = element_ordering_arrays actual_value_arrays = dict(actual_values_elements) if set(actual_value_arrays.keys()) != set(element_ordering_arrays.keys()): msg = 'Names in values arrays do not match those in ordering arrays.' raise ValueError(msg) # Define element priorities from ordering, to choose between equally good # structures, as structure code does not recognise any element ordering. n_elements = len(ordering_elements) element_priorities = { name: n_elements - index for index, (name, array) in enumerate(ordering_elements) } # Calculate the basic fields-group array structure. base_structure = GroupStructure.from_component_arrays( element_ordering_arrays) # Work out the target cube structure. target_structure = _optimal_dimensioning_structure(base_structure, element_priorities) # Work out result cube dimensions. if not target_structure: # Get the length of an input array (they are all the same). # Note that no elements map to multiple dimensions. elements_length = len(ordering_elements[0][1]) vector_dims_shape = (elements_length, ) else: vector_dims_shape = tuple(struct.size for (_, struct) in target_structure) # Build arrays of element values mapped onto the vectorised dimensions. elements_and_dimensions = base_structure.build_arrays( vector_dims_shape, actual_value_arrays) # Filter out the trivial (scalar) ones. elements_and_dimensions = { name: (array, dims) for name, (array, dims) in elements_and_dimensions.items() if len(dims) } # Make a list of 'primary' elements; i.e. those in the target structure. primary_dimension_elements = set(name for (name, _) in target_structure) if vector_dims_shape == (1, ): shape = () else: shape = vector_dims_shape # Return all the information. return (shape, primary_dimension_elements, elements_and_dimensions)
def optimal_array_structure(ordering_elements, actual_values_elements=None): """ Calculate an optimal array replication structure for a set of vectors. Args: * ordering_elements (iterable of (name, 1-d array)): Input element names and value-vectors. Must all be the same length (but not necessarily type). Must have at least one. Kwargs: * actual_values_elements (iterable of (name, 1-d array)): The 'real' values used to construct the result arrays, if different from 'ordering_elements'. Must contain all the same names (but not necessarily in the same order). The 'ordering_elements' arg contains the pattern used to deduce a structure. The order of this is significant, in that earlier elements get priority when associating dimensions with specific elements. Returns: dims_shape, primary_elements, element_arrays_and_dims, where: * 'dims_shape' is the shape of the vector dimensions chosen. * 'primary_elements' is a set of dimension names; the names of input elements that are identified as dimensions. At most one for each dimension. * 'element_arrays_and_dims' is a dictionary [name: (array, dims)], for all elements that are not dimensionless. Each array is reduced to the shape of its mapped dimension. For example:: >>> import iris.fileformats.um._optimal_array_structuring as optdims >>> elements_structure = [('a', np.array([1, 1, 1, 2, 2, 2])), ... ('b', np.array([0, 1, 2, 0, 1, 2])), ... ('c', np.array([11, 12, 13, 14, 15, 16]))] >>> elements_values = [('a', np.array([10, 10, 10, 12, 12, 12])), ... ('b', np.array([15, 16, 17, 15, 16, 17])), ... ('c', np.array([9, 3, 5, 2, 7, 1]))] >>> dims_shape, dim_names, arrays_and_dims = \ ... optdims.optimal_array_structure(elements_structure, ... elements_values) >>> print dims_shape (2, 3) >>> print dim_names set(['a', 'b']) >>> print arrays_and_dims {'a': (array([10, 12]), (0,)), 'c': (array([[9, 3, 5], [2, 7, 1]]), (0, 1)), 'b': (array([15, 16, 17]), (1,))} """ # Convert the inputs to dicts. element_ordering_arrays = dict(ordering_elements) if actual_values_elements is None: actual_values_elements = element_ordering_arrays actual_value_arrays = dict(actual_values_elements) if set(actual_value_arrays.keys()) != set(element_ordering_arrays.keys()): msg = 'Names in values arrays do not match those in ordering arrays.' raise ValueError(msg) # Define element priorities from ordering, to choose between equally good # structures, as structure code does not recognise any element ordering. n_elements = len(ordering_elements) element_priorities = { name: n_elements - index for index, (name, array) in enumerate(ordering_elements)} # Calculate the basic fields-group array structure. base_structure = GroupStructure.from_component_arrays( element_ordering_arrays) # Work out the target cube structure. target_structure = _optimal_dimensioning_structure(base_structure, element_priorities) # Work out result cube dimensions. if not target_structure: # Get the length of an input array (they are all the same). # Note that no elements map to multiple dimensions. elements_length = len(ordering_elements[0][1]) vector_dims_shape = (elements_length,) else: vector_dims_shape = tuple( struct.size for (_, struct) in target_structure) # Build arrays of element values mapped onto the vectorised dimensions. elements_and_dimensions = base_structure.build_arrays( vector_dims_shape, actual_value_arrays) # Filter out the trivial (scalar) ones. elements_and_dimensions = { name: (array, dims) for name, (array, dims) in six.iteritems(elements_and_dimensions) if len(dims)} # Make a list of 'primary' elements; i.e. those in the target structure. primary_dimension_elements = set( name for (name, _) in target_structure) if vector_dims_shape == (1,): shape = () else: shape = vector_dims_shape # Return all the information. return (shape, primary_dimension_elements, elements_and_dimensions)
def test_different_sizes(self): arrays = {'a': np.arange(6), 'b': np.arange(5)} msg = 'All array elements must have the same size.' with self.assertRaisesRegexp(ValueError, msg): GroupStructure.from_component_arrays(arrays)