All Downloads are FREE. Search and download functionalities are using the official Maven repository.

water.rapids.ASTNumList Maven / Gradle / Ivy

There is a newer version: 3.8.2.9
Show newest version
package water.rapids;

import water.H2O;
import water.util.ArrayUtils;
import water.util.SB;

import java.util.ArrayList;
import java.util.Arrays;

/** A collection of base/stride/cnts.  
 *  Syntax: { {num | num:cnt | num:cnt:stride},* }
 *
 *  The bases can be unordered with dups (often used for column selection where
 *  repeated columns are allowed, and order matters).  The _isList flag tracks
 *  that all cnts are 1 (and hence all strides are ignored and 1); these lists
 *  may or may not be sorted.  Note that some column selection is dense
 *  (typical all-columns is: {0:MAX_INT}), and this has cnt>1.
 *
 *  When cnts are > 1, bases must be sorted, with base+stride*cnt always less
 *  than the next base.  Typical use-case might be a list of probabilities for
 *  computing quantiles, or grid-search parameters.
 * 
 *  Asking for a sorted integer expansion will sort the bases internally, and
 *  also demand no overlap between bases.  The has(), min() and max() calls
 *  require a sorted list.
 */
public class ASTNumList extends ASTParameter {
  final double _bases[], _strides[];
  final long _cnts[];
  final boolean _isList; // True if an unordered list of numbers (cnts are 1, stride is ignored)
        boolean _isSort; // True if bases are sorted.  May get updated later.
  
  ASTNumList( Exec e ) {
    ArrayList bases  = new ArrayList<>();
    ArrayList strides= new ArrayList<>();
    ArrayList   cnts   = new ArrayList<>();

    // Parse a number list
    while( true ) {
      char c = e.skipWS();
      if( c==']' ) break;
      if( c=='#' ) e._x++;
      double base = e.number(), cnt=1, stride=1;
      c = e.skipWS();
      if( c==':' ) {
        e.xpeek(':'); e.skipWS();
        cnt = e.number();
        if( cnt < 1 || ((long)cnt) != cnt )
          throw new IllegalArgumentException("Count must be a integer larger than zero, "+cnt);
        c = e.skipWS();
        if( c==':' ) {
          e.xpeek(':'); e.skipWS();
          stride = e.number();
          if( stride < 0 )
            throw new IllegalArgumentException("Stride must be positive, "+stride);
          c = e.skipWS();
        }
      }
      if( cnt==1 && stride != 1 ) throw new IllegalArgumentException("If count is 1, then stride must be one (and ignored)");
      bases.add(base);
      cnts.add((long)cnt);  
      strides.add(stride);
      // Optional comma seperating span
      if( c==',') e.xpeek(',');
    }
    e.xpeek(']');

    // Convert fixed-sized arrays
    _bases  = new double[bases.size()];
    _strides= new double[bases.size()];
    _cnts   = new long  [bases.size()];
    boolean isList = true;
    for( int i=0; i<_bases.length; i++ ) {
      _bases  [i] = bases  .get(i);
      _cnts   [i] = cnts   .get(i);
      _strides[i] = strides.get(i);
      if( _cnts[i] != 1 ) isList = false;
    }
    _isList = isList;

    // Complain about unordered bases, unless it's a simple number list
    boolean isSort = true;
    for( int i=1; i<_bases.length; i++ )
      if( _bases[i-1] >= _bases[i] )
        if( _isList ) isSort = false;
        else throw new IllegalArgumentException("Bases must be monotonically increasing");
    _isSort = isSort;
  }

  // A simple ASTNumList of 1 number
  ASTNumList( double d ) {
    _bases  = new double[]{d};
    _strides= new double[]{1};
    _cnts   = new long  []{1};
    _isList = _isSort = true;
  }
  // A simple dense range ASTNumList
  ASTNumList( long lo, long hi_exclusive ) {
    _bases  = new double[]{lo};
    _strides= new double[]{1};
    _cnts   = new long  []{hi_exclusive-lo};
    _isList = false;
    _isSort = true;
  }

  // An empty number list
  ASTNumList( ) {
    _bases  = new double[0];
    _strides= new double[0];
    _cnts   = new long  [0];
    _isList = _isSort = true;
  }

  ASTNumList(double[] list) {
    _bases  = list;
    _strides= new double[list.length];
    _cnts   = new long[list.length];
    _isList = true;
    Arrays.fill(_strides,1);
    Arrays.fill(_cnts,1);
  }

  ASTNumList(int[] list) {
    this(ArrayUtils.copyFromIntArray(list));
  }

  // This is a special syntatic form; the number-list never executes and hits
  // the execution stack
  @Override
  public Val exec(Env env) { throw new IllegalArgumentException("Number list not allowed here"); }

  @Override public String str() { 
    SB sb = new SB().p('[');
    for( int i=0; i<_bases.length; i++ ) {
      sb.p(_bases[i]);
      if( _cnts[i] != 1 ) {
        sb.p(':').p(_bases[i]+_cnts[i]*_strides[i]);
        if( _strides[i] != 1 || ((long)_bases[i])!=_bases[i] )
          sb.p(':').p(_strides[i]);
      }
      if( i < _bases.length-1 ) sb.p(',');
    }
    return sb.p(']').toString();
  }
  // Strange count of args, due to custom parsing
  @Override int nargs() { return -1; }
  @Override public String toJavaString() {
    double[] ary = expand();
    if( ary==null || ary.length==0 ) return "\"null\"";
    SB sb = new SB().p('{');
    for(int i=0;i= 0 ) return true;
    idx = -idx-2;  // See Arrays.binarySearch; returns (-idx-1), we want +idx-1  ... if idx == -1 => then this transformation has no effect
    if( idx < 0 ) return false;
    assert _bases[idx] < v;     // Sanity check binary search, AND idx >= 0
    return v < _bases[idx]+_cnts[idx]*_strides[idx];
  }

  // Select columns by number.  Numbers are capped to the number of columns +1
  // - this allows R      to see a single out-of-range value and throw a range check
  // - this allows Python to see a single out-of-range value and ignore it
  // - this allows Python to pass [0:MAXINT] without blowing out the max number of columns.
  // Note that the Python front-end does not want to cap the max column size, because
  // this will force eager evaluation on a standard column slice operation.
  // Note that the list is often unsorted (_isSort is false).
  // Note that the list is often dense with cnts>1 (_isList is false).
  @Override int[] columns( String[] names ) {
    // Count total values, capped by max len+1
    int nrows=0, r=0;
    for( int i=0; i<_bases.length; i++ )
      nrows += Math.min(_bases[i]+_cnts[i],names.length+1) - Math.min(_bases[i],names.length+1);
    // Fill in values
    int[] vals = new int[nrows];
    for( int i=0; i<_bases.length; i++ ) {
      int lim = Math.min((int)(_bases[i]+_cnts[i]),names.length+1);
      for( int d = Math.min((int)_bases[i],names.length+1); d




© 2015 - 2025 Weber Informatics LLC | Privacy Policy