    001/*-
    002 *******************************************************************************
    003 * Copyright (c) 2011, 2016 Diamond Light Source Ltd.
    004 * All rights reserved. This program and the accompanying materials
    005 * are made available under the terms of the Eclipse Public License v1.0
    006 * which accompanies this distribution, and is available at
    007 * http://www.eclipse.org/legal/epl-v10.html
    008 *
    009 * Contributors:
    010 *    Peter Chang - initial API and implementation and/or initial documentation
    011 *******************************************************************************/
    012
    013package org.eclipse.january.dataset;
    014
    015import java.util.ArrayList;
    016import java.util.Arrays;
    017import java.util.List;
    018
    019import org.eclipse.january.DatasetException;
    020import org.slf4j.Logger;
    021import org.slf4j.LoggerFactory;
    022
    023/**
    024 * Mathematics class for lazy datasets
    025 */
    026public final class LazyMaths {
    027        /**
    028         * Setup the logging facilities
    029         */
    030        protected static final Logger logger = LoggerFactory.getLogger(LazyMaths.class);
    031
    032        /**
    033         * @param data
    034         * @param axis (can be negative)
    035         * @return sum along axis in lazy dataset
    036         * @throws DatasetException
    037         */
    038        public static Dataset sum(final ILazyDataset data, int axis) throws DatasetException {
    039                if (data instanceof Dataset)
    040                        return ((Dataset) data).sum(axis);
    041                int[][] sliceInfo = new int[3][];
    042                int[] shape = data.getShape();
    043                final Dataset result = prepareDataset(axis, shape, sliceInfo);
    044
    045                final int[] start = sliceInfo[0];
    046                final int[] stop = sliceInfo[1];
    047                final int[] step = sliceInfo[2];
    048                final int length = shape[axis];
    049
    050                for (int i = 0; i < length; i++) {
    051                        start[axis] = i;
    052                        stop[axis] = i + 1;
    053                        result.iadd(data.getSlice(start, stop, step));
    054                }
    055
    056                result.setShape(ShapeUtils.squeezeShape(shape, axis));
    057                return result;
    058        }
    059
    060        /**
    061         * @param data
    062         * @param ignoreAxes axes to ignore
    063         * @return sum when given axes are ignored in lazy dataset
    064         * @throws DatasetException
    065         * @since 2.0
    066         */
    067        public static Dataset sum(final ILazyDataset data, int... ignoreAxes) throws DatasetException {
    068                return sum(data, true, ignoreAxes);
    069        }
    070
    071        /**
    072         * @param data
    073         * @param ignore if true, ignore the provided axes, otherwise use only the provided axes
    074         * @param axes axes to ignore or accept, depending on the preceding flag
    075         * @return sum
    076         * @throws DatasetException
    077         * @since 2.0
    078         */
    079        public static Dataset sum(final ILazyDataset data, boolean ignore, int... axes) throws DatasetException {
    080                Arrays.sort(axes); // ensure they are properly sorted
    081
    082                ILazyDataset rv = data;
    083
    084                if (ignore) {
    085                        List<Integer> goodAxes = new ArrayList<Integer>();
    086                        for (int i = 0 ; i < data.getRank() ; i++) {
    087                                boolean found = false;
    088                                for (int j = 0 ; j < axes.length ; j++) {
    089                                        if (i == axes[j]) {
    090                                                found = true;
    091                                                break;
    092                                        }
    093                                }
    094                                if (!found)
    095                                        goodAxes.add(i);
    096                        }
    097
    098                        for (int i = 0 ; i < goodAxes.size() ; i++) {
    099                                rv = sum(rv, goodAxes.get(i) - i);
    100                        }
    101                } else {
    102                        for (int i = 0 ; i < axes.length ; i++) {
    103                                rv = sum(rv, axes[i] - i);
    104                        }
    105                }
    106                return DatasetUtils.sliceAndConvertLazyDataset(rv);
    107        }
    108
    109        /**
    110         * @param data
    111         * @param axis (can be negative)
    112         * @return product along axis in lazy dataset
    113         * @throws DatasetException
    114         */
    115        public static Dataset product(final ILazyDataset data, int axis) throws DatasetException {
    116                int[][] sliceInfo = new int[3][];
    117                int[] shape = data.getShape();
    118                final Dataset result = prepareDataset(axis, shape, sliceInfo);
    119                result.fill(1);
    120
    121                final int[] start = sliceInfo[0];
    122                final int[] stop = sliceInfo[1];
    123                final int[] step = sliceInfo[2];
    124                final int length = shape[axis];
    125
    126                for (int i = 0; i < length; i++) {
    127                        start[axis] = i;
    128                        stop[axis] = i + 1;
    129                        result.imultiply(data.getSlice(start, stop, step));
    130                }
    131
    132                result.setShape(ShapeUtils.squeezeShape(shape, axis));
    133                return result;
    134        }
    135
    136        /**
    137         * @param start
    138         * @param stop inclusive
    139         * @param data
    140         * @param ignoreAxes
    141         * @return mean when given axes are ignored in lazy dataset
    142         * @throws DatasetException
    143         */
    144        public static Dataset mean(int start, int stop, ILazyDataset data, int... ignoreAxes) throws DatasetException {
    145                int[] shape = data.getShape();
    146                PositionIterator iter = new PositionIterator(shape, ignoreAxes);
    147                int[] pos = iter.getPos();
    148                boolean[] omit = iter.getOmit();
    149
    150                int rank = shape.length;
    151                int[] st = new int[rank];
    152                Arrays.fill(st, 1);
    153                int[] end = new int[rank];
    154
    155                RunningAverage av = null;
    156                int c = 0;
    157                while (iter.hasNext() && c < stop) {
    158                        if (c++ < start) continue;
    159                        for (int i = 0; i < rank; i++) {
    160                                end[i] = omit[i] ? shape[i] : pos[i] + 1;
    161                        }
    162                        IDataset ds = data.getSlice(pos, end, st);
    163                        if (av == null) {
    164                                av = new RunningAverage(ds);
    165                        } else {
    166                                av.update(ds);
    167                        }
    168                }
    169
    170                return  av != null ? av.getCurrentAverage().squeeze() : null;
    171        }
    172
    173        public static Dataset mean(ILazyDataset data, int... ignoreAxes) throws DatasetException {
    174                return mean(0, Integer.MAX_VALUE -1 , data, ignoreAxes);
    175        }
    176
    177        @SuppressWarnings("deprecation")
    178        private static Dataset prepareDataset(int axis, int[] shape, int[][] sliceInfo) {
    179                int rank = shape.length;
    180                if (axis < 0)
    181                        axis += rank;
    182                if (axis < 0 || axis >= rank) {
    183                        logger.error("Axis argument is outside allowed range");
    184                        throw new IllegalArgumentException("Axis argument is outside allowed range");
    185                }
    186
    187                sliceInfo[0] = new int[rank];
    188                sliceInfo[1] = shape.clone();
    189                sliceInfo[2] = new int[rank];
    190                Arrays.fill(sliceInfo[2], 1);
    191
    192                final int[] nshape = shape.clone();
    193                nshape[axis] = 1;
    194
    195                return DatasetFactory.zeros(nshape, Dataset.FLOAT64);
    196        }
    197}