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}