package dods.clients.matlab; import dods.dap.*; import java.lang.*; /** * An extention of the DArray class, with optimizations for Matlab. * * @see DArray */ public class MatlabArray extends DArray { /** * Construct a new <code>MatlabArray</code>. */ public MatlabArray() { super(); } /** * Construct a new <code>MatlabArray</code> with name <code>name</code>. * @param name The name of the array */ public MatlabArray(String name) { super(name); } /** * Return the type of data held in the array as a <code>String</code>. * @return The type of data held in the array. */ public String getArrayTypeName() { PrimitiveVector pv = getPrimitiveVector(); BaseType varTemplate = pv.getTemplate(); return varTemplate.getTypeName(); } /** * Return the data held in the MatlabArray as an array of * atomic types. * @return The data. */ public Object getData() { PrimitiveVector pv = getPrimitiveVector(); if( (pv instanceof BaseTypePrimitiveVector) == false) return pv.getInternalStorage(); else { BaseTypePrimitiveVector basePV = (BaseTypePrimitiveVector)pv; BaseType varTemplate = (BaseType)basePV.getValue(0); if(varTemplate instanceof MatlabString) { char[][] arrayData = new char[basePV.getLength()][]; for(int i=0;i<pv.getLength();i++) { arrayData[i] = ((MatlabString)basePV.getValue(i)).getValue().toCharArray(); } return arrayData; } else if(varTemplate instanceof MatlabURL) { char[][] arrayData = new char[basePV.getLength()][]; for(int i=0;i<pv.getLength();i++) { arrayData[i] = ((MatlabURL)basePV.getValue(i)).getValue().toCharArray(); } return arrayData; } else return null; } } /** * The following functions are taken almost verbatim from extend.c * in C++ matlab client distribution. */ /** * Given an index into, and the dimensions of the array, return the offset * needed to access the referenced element assuming row-major storage * order. * @param current_index The index to retrieve the offset for * @param ndims The number of dimensions * @param dims An array containing The dimensions of the array * @return The offset needed to retrieve <code>current_index</code> from * a single-dimension array in row-major order. */ protected static int get_rm_offset(int[] current_index, int ndims, int[] dims) { int offset = 0; int j, k, t; for (j = 0; j < ndims; ++j) { t = 1; for (k = j+1; k < ndims; ++k) t *= dims[k]; offset += current_index[j] * t; } return offset; } /** * Given an index into, and the dimensions of the array, return the offset * needed to access the referenced element assuming column-major storage * order. * @param current_index The index to retrieve the offset for * @param ndims The number of dimensions * @param dims An array containing the dimensions of the array * @return The offset needed to retrieve <code>current_index</code> from * a single-dimension array in column-major order. */ protected static int get_cm_offset(int[] current_index, int ndims, int[] dims) { int offset = 0; int j, k, t; for (j = 0; j < ndims; ++j) { t = 1; for (k = 0; k < j; ++k) t *= dims[k]; offset += current_index[j] * t; } return offset; } /** * Given the double array described by rm_dims[ndims], transform that array * from row-major to column-major order. Put the result in dest. * <p> * Assume that the rm_dims array contains the dimension information in * row-major order. * * @param src The column-major array to convert to row-major * @param ndims The number of dimensions in the array * @param dims An array containing the dimensions of the array */ public static double[] rm2cm(double[] src, int ndims, int rm_dims[]) { int[] cm_index; int[] rm_index; int[] cm_dims; int num_elements = 1; int rm_offset, cm_offset; double[] dest; for(int i=0;i<ndims;i++) { num_elements *= rm_dims[i]; } dest = new double[num_elements]; if (ndims <= 2) { /** * An optimization: when ndims is 0, 1 or 2 then the rm and cm * index order is the same. Only transform the indices when * ndims is > 2. */ rm_index = new int[ndims]; do { rm_offset = get_rm_offset(rm_index, ndims, rm_dims); cm_offset = get_cm_offset(rm_index, ndims, rm_dims); dest[cm_offset] = src[rm_offset]; } while (get_next_rm_index(rm_index, ndims, rm_dims)); } else { cm_index = new int[ndims]; rm_index = new int[ndims]; cm_dims = new int[ndims]; rm_index2cm_index(cm_dims, rm_dims, ndims); do { rm_offset = get_rm_offset(rm_index, ndims, rm_dims); rm_index2cm_index(cm_index, rm_index, ndims); cm_offset = get_cm_offset(cm_index, ndims, cm_dims); dest[cm_offset] = src[rm_offset]; } while (get_next_rm_index(rm_index, ndims, rm_dims)); } return dest; } /** * Given the row-major index array (with ndims-1 elements), load values into * cm_dims so that the dimensions will be listed in Matlab's n-major order. * <p> * Assume that enough storage has already been allocated to cm_dims. * <p><code> * Algorithm: RM order: Plane, Row, Column<br> * NM order: Row, Column, Plane. * </code><p> * Move the last two dimensions from the RM order to the first two of the NM * order. Then copy each plane dimension from the front of the RM ordering * to the back of the NM ordering reversing those entries as they are * copied. * <p> * Note that if ndims is less then three then this function just copies the * values and, in that case, it is better to not use this function. * * @param cm_dims An array for which the appropriate memory has been already * allocated to store the column-major dimensions in * @param rm_dims An array containing the row-major dimensions to be * converted into column-major * @param ndims The number of dimensions */ protected static void rm_index2cm_index(int[] cm_dims, int[] rm_dims, int ndims) { switch(ndims) { case 1: cm_dims[0] = rm_dims[0]; break; case 2: cm_dims[0] = rm_dims[0]; cm_dims[1] = rm_dims[1]; break; default: { /* ndims >= 3 */ int i, j; cm_dims[0] = rm_dims[ndims-2]; cm_dims[1] = rm_dims[ndims-1]; /* Copy and reverse the plane (or page) entries */ /* What this loop does: P0 P1 P2 R C <-- ^ | i Start i at P2 and move it towards the front of the rm_dims array. Tack each plane index P* onto the end of cm_dims so that the final ordering looks like: R C P2 P1 P0 */ j = 2; for (i = ndims-3; i >= 0; i--) cm_dims[j++] = rm_dims[i]; break; } } } /** * A public interface to rm_index2cm_index which doesn't require * memory to be allocated for the array containing the column-major * dimensions * * @param rm_dims An array containing the row-major dimensions to be * converted into column-major * @param ndims The number of dimensions * @return An array containing the column-major dimensions */ public static int[] rm_index2cm_index(int[] rm_dims, int ndims) { int[] cm_dims = new int[ndims]; rm_index2cm_index(cm_dims, rm_dims, ndims); return cm_dims; } /** * Given a current index tuple and the dimensionality of the data, compute * the next tuple. Vary the rightmost element of the tuple the fastest. * Return true if there *is* a next tuple (which is passed back in * current_index), false otherwise. * * @param current_index An array containing the rm index to be incremented * @param ndims The number of dimensions in the array * @param dims An array containing the dimensions of the array. */ protected static boolean get_next_rm_index(int[] current_index, int ndims, int[] dims) { int i; for (i = ndims-1; i >= 0; --i) { current_index[i]++; if (current_index[i] < dims[i]) return true; else current_index[i] = 0; } return false; } };