public static void assertVector(INDArray arr) { if (!arr.isVector()) throw new IllegalArgumentException("Array must be a vector. Array has shape: " + Arrays.toString(arr.shape())); }
/** Check if strides are in order suitable for non-strided mmul etc. * Returns true if c order and strides are descending [100,10,1] etc * Returns true if f order and strides are ascending [1,10,100] etc * False otherwise. * @return true if c+descending, f+ascending, false otherwise */ public static boolean strideDescendingCAscendingF(INDArray array) { long[] strides = array.stride(); if (array.isVector() && strides[0] == 1 && strides[1] == 1) return true; char order = array.ordering(); if (order == 'c') { //Expect descending. [100,10,1] etc for (int i = 1; i < strides.length; i++) if (strides[i - 1] <= strides[i]) return false; return true; } else if (order == 'f') {//Expect ascending. [1,10,100] etc for (int i = 1; i < strides.length; i++) if (strides[i - 1] >= strides[i]) return false; return true; } else if (order == 'a') { return true; } else { throw new RuntimeException("Invalid order: not c or f (is: " + order + ")"); } }
/** * Reshapes an ndarray to remove leading 1s * @param toStrip the ndarray to newShapeNoCopy * @return the reshaped ndarray */ public static INDArray stripOnes(INDArray toStrip) { if (toStrip.isVector()) return toStrip; else { long[] shape = Shape.squeeze(toStrip.shape()); return toStrip.reshape(shape); } }
/** * Get the leading dimension * for a blas invocation. * * The lead dimension is usually * arr.size(0) (this is only for fortran ordering though). * It can be size(1) (assuming matrix) for C ordering though. * @param arr the array to * @return the leading dimension wrt the ordering of the array * */ public static int getLd(INDArray arr) { //ignore ordering for vectors if (arr.isVector()) { return (int) arr.length(); } return arr.ordering() == NDArrayFactory.C ? (int) arr.size(1) : (int) arr.size(0); }
@Override public INDArray putRow(long row, INDArray toPut) { if (isRowVector() && toPut.isVector()) { return assign(toPut); } return put(new INDArrayIndex[] {NDArrayIndex.point(row), NDArrayIndex.all()}, toPut); }
@Override public INDArray putColumn(int column, INDArray toPut) { if (isColumnVector() && toPut.isVector()) { return assign(toPut); } return put(new INDArrayIndex[] {NDArrayIndex.all(), NDArrayIndex.point(column)}, toPut); }
@Override public boolean equalsWithEps(Object o, double eps) { if (o == null) return false; if (!(o instanceof INDArray)) return false; INDArray n = (INDArray) o; if (this.lengthLong() != n.lengthLong()) return false; if (isScalar() && n.isScalar()) { // TODO } else if (isVector && n.isVector()) { // TODO } if (!Arrays.equals(this.shape(), n.shape())) return false; // TODO return false; }
/** * Insert a row in to this array * Will throw an exception if this * ndarray is not a matrix * * @param row the row insert into * @param toPut the row to insert * @return this */ @Override public INDArray putRow(long row, INDArray toPut) { if (isRowVector() && toPut.isVector()) { return assign(toPut); } return put(new INDArrayIndex[] {NDArrayIndex.point(row), NDArrayIndex.all()}, toPut); }
protected void assertSlice(INDArray put, long slice) { assert slice <= slices() : "Invalid slice specified " + slice; long[] sliceShape = put.shape(); if (Shape.isRowVectorShape(sliceShape)) { return; } else { long[] requiredShape = ArrayUtil.removeIndex(shape(), 0); //no need to compare for scalar; primarily due to shapes either being [1] or length 0 if (put.isScalar()) return; if (isVector() && put.isVector() && put.length() < length()) return; //edge case for column vectors if (Shape.isColumnVectorShape(sliceShape)) return; if (!Shape.shapeEquals(sliceShape, requiredShape) && !Shape.isRowVectorShape(requiredShape) && !Shape.isRowVectorShape(sliceShape)) throw new IllegalStateException(String.format("Invalid shape size of %s . Should have been %s ", Arrays.toString(sliceShape), Arrays.toString(requiredShape))); } }
@Override public INDArray put(INDArrayIndex[] indices, INDArray element) { if (indices[0] instanceof SpecifiedIndex && element.isVector()) { indices[0].reset(); int cnt = 0; while (indices[0].hasNext()) { long idx = indices[0].next(); putScalar((int) idx, element.getDouble(cnt)); cnt++; } return this; } else { return get(indices).assign(element); } }
/** * Insert a column in to this array * Will throw an exception if this * ndarray is not a matrix * * @param column the column to insert * @param toPut the array to put * @return this */ @Override public INDArray putColumn(int column, INDArray toPut) { Nd4j.getCompressor().autoDecompress(this); if (isColumnVector() && toPut.isVector()) { return assign(toPut); } return put(new INDArrayIndex[] {NDArrayIndex.all(), NDArrayIndex.point(column)}, toPut); }
/** Can we do the op (X = Op(X)) directly on the arrays without breaking X up into 1d tensors first? * In general, this is possible if the elements of X are contiguous in the buffer, OR if every element * of X is at position offset+i*elementWiseStride in the buffer * */ public static boolean canDoOpDirectly(INDArray x) { if (x.elementWiseStride() < 1) return false; if (x.isVector()) return true; //For a single NDArray all we require is that the elements are contiguous in the buffer or every nth element //Full buffer -> implies all elements are contiguous (and match) long l1 = x.lengthLong(); long dl1 = x.data().length(); if (l1 == dl1) return true; //Strides are same as a zero offset NDArray -> all elements are contiguous (even if not offset 0) long[] shape1 = x.shape(); long[] stridesAsInit = (x.ordering() == 'c' ? ArrayUtil.calcStrides(shape1) : ArrayUtil.calcStridesFortran(shape1)); boolean stridesSameAsInit = Arrays.equals(x.stride(), stridesAsInit); return stridesSameAsInit; }
/** * Get the dimension associated with * the given ordering. * * When working with blas routines, they typically assume * c ordering, instead you can invert the rows/columns * which enable you to do no copy blas operations. * * * * @param arr * @param defaultRows * @return */ public static int getDimension(INDArray arr, boolean defaultRows) { // FIXME: int cast //ignore ordering for vectors if (arr.isVector()) { return defaultRows ? (int) arr.rows() : (int) arr.columns(); } if (arr.ordering() == NDArrayFactory.C) return defaultRows ? (int) arr.columns() : (int) arr.rows(); return defaultRows ? (int) arr.rows() : (int) arr.columns(); }
@Override public INDArray put(INDArrayIndex[] indices, INDArray element) { Nd4j.getCompressor().autoDecompress(this); if (indices[0] instanceof SpecifiedIndex && element.isVector()) { indices[0].reset(); int cnt = 0; while (indices[0].hasNext()) { long idx = indices[0].next(); // FIXME: LONG putScalar((int) idx, element.getDouble(cnt)); cnt++; } return this; } else { return get(indices).assign(element); } }
/** * Reverses the passed in matrix such that m[0] becomes m[m.length - 1] etc * * @param reverse the matrix to reverse * @return the reversed matrix */ @Override public INDArray rot(INDArray reverse) { INDArray ret = Nd4j.create(reverse.shape()); if (reverse.isVector()) return reverse(reverse); else { for (int i = 0; i < reverse.slices(); i++) { ret.putSlice(i, reverse(reverse.slice(i))); } } return ret.reshape(reverse.shape()); }
/** * Get the vector along a particular dimension * * @param index the index of the vector to get * @param dimension the dimension to get the vector from * @return the vector along a particular dimension */ @Override public INDArray vectorAlongDimension(int index, int dimension) { if (dimension < 0) dimension = Shape.rank(javaShapeInformation) + dimension; //return the whole thing if (dimension == Shape.rank(javaShapeInformation) - 1 && size(dimension) == 1 && rank() > 2 || rank() > 2 && dimension == 0 && size(dimension) == 1) { return this; } INDArray ret = tensorAlongDimension(index, dimension); if (isMatrix() && ret.isVector() && dimension == 1 && !ret.isRowVector()) return ret.reshape(ArrayUtil.reverseCopy(ret.shape())); else if (isMatrix() && ret.isVector() && dimension == 0 && !ret.isColumnVector()) return ret.reshape(ArrayUtil.reverseCopy(ret.shape())); return ret; }
/** * Create from a matrix. The rows are the indices * The columns are the individual element in each ndarrayindex * * @param index the matrix to getFloat indices from * @return the indices to getFloat */ public static INDArrayIndex[] create(INDArray index) { if (index.isMatrix()) { if (index.rows() > Integer.MAX_VALUE) throw new ND4JArraySizeException(); NDArrayIndex[] ret = new NDArrayIndex[(int) index.rows()]; for (int i = 0; i < index.rows(); i++) { INDArray row = index.getRow(i); val nums = new long[(int) index.getRow(i).columns()]; for (int j = 0; j < row.columns(); j++) { nums[j] = (int) row.getFloat(j); } NDArrayIndex idx = new NDArrayIndex(nums); ret[i] = idx; } return ret; } else if (index.isVector()) { long[] indices = NDArrayUtil.toLongs(index); return new NDArrayIndex[] {new NDArrayIndex(indices)}; } throw new IllegalArgumentException("Passed in ndarray must be a matrix or a vector"); }
/** * Insert a column in to this array * Will throw an exception if this * ndarray is not a matrix * * @param column the column to insert * @param toPut the array to put * @return this */ @Override public IComplexNDArray putColumn(int column, INDArray toPut) { assert toPut.isVector() && toPut.length() == rows() : "Illegal length for row " + toPut.length() + " should have been " + columns(); IComplexNDArray r = getColumn(column); if (toPut instanceof IComplexNDArray) { IComplexNDArray putComplex = (IComplexNDArray) toPut; for (int i = 0; i < r.length(); i++) { IComplexNumber n = putComplex.getComplex(i); r.putScalar(i, n); } } else { for (int i = 0; i < r.length(); i++) r.putScalar(i, Nd4j.createDouble(toPut.getDouble(i), 0)); } return this; }
@Override public void gemv(char order, char transA, double alpha, INDArray A, INDArray X, double beta, INDArray Y) { checkArgument(A.isMatrix(), "A must be a matrix"); checkArgument(X.isVector(), "X must be a vector"); checkArgument(Y.isVector(), "Y must be a vector"); SparseCOOGemvParameters parameters = new SparseCOOGemvParameters(A, X, Y); switch (A.data().dataType()) { case DOUBLE: DefaultOpExecutioner.validateDataType(DataBuffer.Type.DOUBLE, parameters.getA(), parameters.getX(), parameters.getY()); dcoomv(parameters.getAOrdering(), parameters.getM(), parameters.getVal(), parameters.getRowInd(), parameters.getColInd(), parameters.getNnz(), parameters.getX(), parameters.getY()); break; case FLOAT: DefaultOpExecutioner.validateDataType(DataBuffer.Type.FLOAT, parameters.getA(), parameters.getX(), parameters.getY()); scoomv(parameters.getAOrdering(), parameters.getM(), parameters.getVal(), parameters.getRowInd(), parameters.getColInd(), parameters.getNnz(), parameters.getX(), parameters.getY()); break; default: throw new UnsupportedOperationException(); } }
/**Choose tensor dimension for operations with 3 arguments: z=Op(x,y) or similar<br> * @see #chooseElementWiseTensorDimension(INDArray) */ public static int chooseElementWiseTensorDimension(INDArray x, INDArray y, INDArray z) { if (x.isVector()) return ArrayUtil.argMax(x.shape()); // FIXME: int cast int opAlongDimensionMinStride = (int) ArrayUtil.argMinOfMax(x.stride(), y.stride(), z.stride()); int opAlongDimensionMaxLength = ArrayUtil.argMax(x.shape()); //Edge case: shapes with 1s in them can have stride of 1 on the dimensions of length 1 if (opAlongDimensionMinStride == opAlongDimensionMaxLength || x.size((int) opAlongDimensionMinStride) == 1) return opAlongDimensionMaxLength; int nOpsAlongMinStride = ArrayUtil.prod(ArrayUtil.removeIndex(x.shape(), (int) opAlongDimensionMinStride)); int nOpsAlongMaxLength = ArrayUtil.prod(ArrayUtil.removeIndex(x.shape(), opAlongDimensionMaxLength)); if (nOpsAlongMinStride <= 10 * nOpsAlongMaxLength) return opAlongDimensionMinStride; else return opAlongDimensionMaxLength; }