Advertisement
homer512

Optmized multidim reduction

Sep 30th, 2015
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.51 KB | None | 0 0
  1. #!/usr/bin/python2
  2.  
  3. #  Copyright 2015 Florian Philipp
  4. #
  5. #  Licensed under the Apache License, Version 2.0 (the "License");
  6. #  you may not use this file except in compliance with the License.
  7. #  You may obtain a copy of the License at
  8. #
  9. #      http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. #  Unless required by applicable law or agreed to in writing, software
  12. #  distributed under the License is distributed on an "AS IS" BASIS,
  13. #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. #  See the License for the specific language governing permissions and
  15. #  limitations under the License.
  16.  
  17.  
  18. """Demonstrates the combinatoric reduction of multidimensional datasets"""
  19.  
  20.  
  21. import itertools
  22.  
  23. import numpy
  24.  
  25.  
  26. def per_axis_combination(arr, reduce_comb=numpy.prod, eliminate_axis=numpy.sum,
  27.                          odtype=None, remaindim=2):
  28.     """Combines multidimensional datasets into lower dimensional datasets
  29.  
  30.    All combinations of dimensions in the input array are combined using
  31.    repeated calls of eliminate_axis until remaindim dimensions are left.
  32.    Then reduce_comb is called on the final result, once per combination.
  33.  
  34.    Example:
  35.    arr.ndim = 5
  36.    remaindim = 2
  37.    result[0,1] = reduce_comb(combination of axis 2, 3, 4)
  38.    result[0,2] = reduce_comb(combination of axis 1, 3, 4)
  39.    ...
  40.    result[3,4] = reduce_comb(combination of axis 0, 1, 2)
  41.  
  42.    Arguments:
  43.    arr -- a multidimensional numpy array that serves as input
  44.    reduce_comb -- functor that is called in the final reduction stage.
  45.                   The input has remaindim dimensions. The output is expected
  46.                   to be a scalar compatible with odtype
  47.    eliminate_axis -- functor that is called in the first reduction stage.
  48.                      eliminate_axis(N dimensions, axis) -> N-1 dimensions
  49.    odtype -- output data type. Defaults to arr.dtype
  50.    remaindim -- Final dimensionality
  51.  
  52.    Return value:
  53.    An array with dtype=odtype, ndim=remaindim, shape=(arr.ndim,)*remaindim.
  54.    Only the strictly upper triangle (or its higher-dimensional equivalent) is
  55.    filled. The remaining entries are invalid. The indices correspond to the
  56.    combined dimensions
  57.    """
  58.     ndim = arr.ndim
  59.     if ndim < remaindim:
  60.         raise IndexError('insufficient number of axes')
  61.     if odtype is None:
  62.         odtype = arr.dtype
  63.     allaxes = xrange(ndim)
  64.     destinations = reversed(list(itertools.combinations(allaxes, remaindim)))
  65.     results = numpy.empty((ndim, ) * remaindim, odtype)
  66.     finaldepth = ndim - remaindim
  67.     def sum_recurse(outersum, outeraxis=-1):
  68.         """Recursively applies eliminate_axis, then finally reduce_comb
  69.  
  70.        Relevant surrounding variables:
  71.        destinations -- iterator that defines the indizes to which the results
  72.                        are saved. The reduction happens in lexicographical
  73.                        order of the axis numbers, e.g.
  74.                        (0, 1, 2), (0, 1, 3) ... (2, 3, 4), so
  75.                        the index order of destinations has to correspond, i.e.
  76.                        (3, 4), (2, 4) ... (0, 1)
  77.        results -- will be filled with return values of reduce_comb
  78.  
  79.        Arguments:
  80.        outersum -- input array
  81.        outeraxis -- last axis that was eliminated. -1 on initial call
  82.        """
  83.         depth = ndim - outersum.ndim
  84.         if depth == finaldepth:
  85.             results[next(destinations)] = reduce_comb(outersum)
  86.             return
  87.         startaxis = outeraxis + 1
  88.         endaxis = depth + remaindim + 1
  89.         for inneraxis in xrange(startaxis, endaxis):
  90.             # Note that the actual axis numbers differ from the computed
  91.             # numbers because some axes have been eliminated before
  92.             innersum = eliminate_axis(outersum, inneraxis - depth)
  93.             sum_recurse(innersum, inneraxis)
  94.     sum_recurse(arr)
  95.     return results
  96.  
  97.  
  98. def triu_to_full(arr, diagonal=1):
  99.     """Copies the transposition of the upper triangular matrix to the lower
  100.  
  101.    Arguments:
  102.    arr -- array representing a symmetric matrix as a full matrix where only
  103.           the upper triangular matrix is filled with valid values
  104.    diagonal -- number of diagonal above which the values are valid.
  105.                0 means upper triangular, 1 means strictly upper triangular
  106.  
  107.    Return value:
  108.    A copy of the input array where all values are valid. With diagonal == 1,
  109.    the main diagonal is filled with zeros
  110.    """
  111.     zeroed = numpy.triu(arr, diagonal)
  112.     return zeroed + zeroed.T
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement