/* (non-Javadoc)
@see org.joml.Matrix4fc#scaleLocal(float, org.joml.Matrix4f)
329541
public Matrix4f scaleLocal(float xyz, Matrix4f dest) {
        return scaleLocal(xyz, xyz, xyz, dest);
    }
1350816
public static Sprite scale(Sprite original, float scale, ScalingMethod method) {
		if (scale == 1.0f) return original.copy();

		switch (method) {
			case NEAREST:
				return scaleNearest(original, scale);
			case BILINEAR:
				return scaleBilinear(original, scale);
		}

		return null;
	}
1161818
public void scale(double v){
		for(int i = 0; i < this.size(); i++){
			this.get(i).scale(v);;
		}
	}
1098628
public Matrix4f scaleAroundLocal(float factor, float ox, float oy, float oz, Matrix4f dest) {
        return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest);
    }
12920
@Override protected void setupLocal(){
//    long start = System.currentTimeMillis();
    assert(_localmodel == null);
    _localmodel = _sharedmodel;
    _sharedmodel = null;
    _localmodel.set_processed_local(0);
    final int weightIdx =_fr.find(_localmodel.get_params()._weights_column);
    final int respIdx =_fr.find(_localmodel.get_params()._response_column);
    final int batchSize = _localmodel.get_params()._mini_batch_size;

//    long nativetime = 0;
    DeepWaterIterator iter = null;
    long seed = 0xDECAF + 0xD00D * _localmodel.get_processed_global();
    Random rng = RandomUtils.getRNG(seed);

    if (_fr.numRows()>Integer.MAX_VALUE) {
      throw H2O.unimpl("Need to implement batching into int-sized chunks.");
    }
    int len = (int)_fr.numRows();
    int j=0;
    Futures fs = new Futures();
    ArrayList trainLabels = new ArrayList<>();
    ArrayList trainData = new ArrayList<>();

    try {
      // Binary data (Images/Documents/etc.)
      if (_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.image ||
          _localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.text) {
        int dataIdx = 0; //must be the first column //FIXME
        Log.debug("Using column " + _fr.name(dataIdx) + " for " +
            ((_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.image) ? "path to image data"
                :((_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.text) ? "text data"
                : "path to arbitrary bytes")));
        // full passes over the data
        BufferedString bs = new BufferedString();
        int fullpasses = (int)_useFraction; // Example: train_samples_per_iteration = 4700, and train.numRows()=1000 -> _useFraction = 4.7 -> fullpasses = 4
        while (j++ < fullpasses) {
          for (int i=0; i<_fr.numRows(); ++i) {
            double weight = weightIdx == -1 ? 1 : _fr.vec(weightIdx).at(i);
            if (weight == 0)
              continue;
            BufferedString file = _fr.vec(dataIdx).atStr(bs, i);
            if (file!=null)
              trainData.add(file.toString());
            float response = (float) _fr.vec(respIdx).at(i);
            trainLabels.add(response);
          }
        }

        // fractional passes // 0.7
        while (trainData.size() < _useFraction*len || trainData.size() % batchSize != 0) {
          assert(_shuffle);
          int i = rng.nextInt(len);
          double weight = weightIdx == -1 ? 1 : _fr.vec(weightIdx).at(i);
          if (weight == 0)
            continue;
          BufferedString file = _fr.vec(dataIdx).atStr(bs, i);
          if (file!=null)
            trainData.add(file.toString());
          float response = (float) _fr.vec(respIdx).at(i);
          trainLabels.add(response);
        }
      }

      // Numeric data (H2O Frame full with numeric columns)
      else if (_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.dataset) {
        double mul = _localmodel._dataInfo._normRespMul!=null ? _localmodel._dataInfo._normRespMul[0] : 1;
        double sub = _localmodel._dataInfo._normRespSub!=null ? _localmodel._dataInfo._normRespSub[0] : 0;

        // full passes over the data
        int fullpasses = (int) _useFraction;
        while (j++ < fullpasses) {
          for (int i = 0; i < _fr.numRows(); ++i) {
            double weight = weightIdx == -1 ? 1 : _fr.vec(weightIdx).at(i);
            if (weight == 0)
              continue;
            float response = (float)((_fr.vec(respIdx).at(i) - sub) / mul);
            trainData.add(i);
            trainLabels.add(response);
          }
        }

        // fractional passes
        while (trainData.size() < _useFraction * len || trainData.size() % batchSize != 0) {
          int i = rng.nextInt(len);
          double weight = weightIdx == -1 ? 1 : _fr.vec(weightIdx).at(i);
          if (weight == 0)
            continue;
          float response = (float)((_fr.vec(respIdx).at(i) - sub) / mul);
          trainData.add(i);
          trainLabels.add(response);
        }
      }

      // shuffle the (global) list
      if (_shuffle) {
        rng.setSeed(seed);
        Collections.shuffle(trainLabels, rng);
        rng.setSeed(seed);
        Collections.shuffle(trainData, rng);
      }
      if (_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.image) {
        iter = new DeepWaterImageIterator(trainData, trainLabels, _localmodel._meanData, batchSize, _localmodel._width, _localmodel._height, _localmodel._channels, _localmodel.get_params()._cache_data);
      }
      else if (_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.dataset) {
        assert (_localmodel._dataInfo != null);
        iter = new DeepWaterDatasetIterator(trainData, trainLabels, _localmodel._dataInfo, batchSize, _localmodel.get_params()._cache_data);
      }
      else if (_localmodel.get_params()._problem_type == DeepWaterParameters.ProblemType.text) {
        iter = new DeepWaterTextIterator(trainData, trainLabels, batchSize, 56/*FIXME*/, _localmodel.get_params()._cache_data);
      }

      NativeTrainTask ntt;
      while (iter.Next(fs) && !_job.isStopping()) {
//        if (ntt != null) nativetime += ntt._timeInMillis;
        long n = _localmodel.get_processed_total();

//        if(!_localmodel.get_params()._quiet_mode)
//          Log.info("Trained " + n + " samples. Training on " + Arrays.toString(((DeepWaterImageIterator)iter).getFiles()));

        _localmodel._backend.setParameter(_localmodel.getModel().get(), "learning_rate", _localmodel.get_params().learningRate((double) n));
        _localmodel._backend.setParameter(_localmodel.getModel().get(), "momentum", _localmodel.get_params().momentum((double) n));

        //fork off GPU work, but let the iterator.Next() wait on completion before swapping again
        //System.err.println("data: " + Arrays.toString(iter.getData()));
        /*
        float[] preds = _localmodel._backend.predict(_localmodel._model, iter.getData());
        if (Float.isNaN(ArrayUtils.sum(preds))) {
          Log.err(DeepWaterModel.unstable_msg);
          throw new UnsupportedOperationException(DeepWaterModel.unstable_msg);
        }
        */
//        System.err.println("pred: " + Arrays.toString(preds));
        ntt = new NativeTrainTask(_localmodel._backend, _localmodel.getModel().get(), iter.getData(), iter.getLabel());
        fs.add(H2O.submitTask(ntt));
        _localmodel.add_processed_local(iter._batch_size);
      }
      fs.blockForPending();
//      nativetime += ntt._timeInMillis;
    } catch (IOException e) {
      e.printStackTrace(); //gracefully continue if we can't find files etc.
    }
//    long end = System.currentTimeMillis();
//    if (!_localmodel.get_params()._quiet_mode) {
//      Log.info("Time for one iteration: " + PrettyPrint.msecs(end - start, true));
//      Log.info("Time for native training : " + PrettyPrint.msecs(nativetime, true));
//    }
  }
807318
public Matrix4d scale(Vector3dc xyz, Matrix4d dest) {
        return scale(xyz.x(), xyz.y(), xyz.z(), dest);
    }
395299
public Matrix4x3f scale(float xyz, Matrix4x3f dest) {
        return scale(xyz, xyz, xyz, dest);
    }
722674
public Matrix4x3d scale(Vector3dc xyz, Matrix4x3d dest) {
        return scale(xyz.x(), xyz.y(), xyz.z(), dest);
    }
1076546
@Override public void setupLocal() {
    _ok = new int[_files.length];
    for( int i = 0; i < _files.length; ++i ) {
      File f = new File(_files[i]);
      if( f.exists() && (f.length()==_sizes[i]) )
        _ok[i] = 1;
    }
  }
552394
public Matrix3x2f scaleAroundLocal(float factor, float ox, float oy, Matrix3x2f dest) {
        return scaleAroundLocal(factor, factor, ox, oy, dest);
    }
881491
@Override protected void setupLocal(){
    assert(_localmodel == null);
    super.setupLocal();
    if (model_info().get_params()._elastic_averaging) {
      //Load my local model from DKV, to continue training
      _localmodel = DKV.getGet(_sharedmodel.localModelInfoKey(H2O.SELF));
      if (_localmodel != null) {
        if (!Arrays.equals(_localmodel.units, _sharedmodel.units)) {
          _localmodel = IcedUtils.deepCopy(_sharedmodel);
        } else {
          //Make sure that the local model has the right global (shared) parameters after checkpoint restart!
          _localmodel.set_params(_sharedmodel.get_params(), _sharedmodel._model_id);
          _localmodel.set_processed_global(_sharedmodel.get_processed_global());
        }
      }
      else {
        // first time around - use the randomized initial weights and don't spread the shared (random) model
        _localmodel = IcedUtils.deepCopy(_sharedmodel);
        _sharedmodel = null;
      }
    } else {
      _localmodel = _sharedmodel;
      _sharedmodel = null;
    }
    _localmodel.set_processed_local(0);
  }
1003810
public Matrix3x2f scaling(float x, float y) {
        m00 = x;
        m01 = 0.0f;
        m10 = 0.0f;
        m11 = y;
        m20 = 0.0f;
        m21 = 0.0f;
        return this;
    }
168547
public Matrix3d scaleLocal(double x, double y, double z, Matrix3d dest) {
        double nm00 = x * m00;
        double nm01 = y * m01;
        double nm02 = z * m02;
        double nm10 = x * m10;
        double nm11 = y * m11;
        double nm12 = z * m12;
        double nm20 = x * m20;
        double nm21 = y * m21;
        double nm22 = z * m22;
        dest.m00 = nm00;
        dest.m01 = nm01;
        dest.m02 = nm02;
        dest.m10 = nm10;
        dest.m11 = nm11;
        dest.m12 = nm12;
        dest.m20 = nm20;
        dest.m21 = nm21;
        dest.m22 = nm22;
        return dest;
    }
1003226
public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4d dest) {
        double nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
        double nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
        double nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
        double nm33 = m03 * ox + m13 * oy + m23 * oz + m33;
        dest.m00 = m00 * sx;
        dest.m01 = m01 * sx;
        dest.m02 = m02 * sx;
        dest.m03 = m03 * sx;
        dest.m10 = m10 * sy;
        dest.m11 = m11 * sy;
        dest.m12 = m12 * sy;
        dest.m13 = m13 * sy;
        dest.m20 = m20 * sz;
        dest.m21 = m21 * sz;
        dest.m22 = m22 * sz;
        dest.m23 = m23 * sz;
        dest.m30 = -m00 * ox - m10 * oy - m20 * oz + nm30;
        dest.m31 = -m01 * ox - m11 * oy - m21 * oz + nm31;
        dest.m32 = -m02 * ox - m12 * oy - m22 * oz + nm32;
        dest.m33 = -m03 * ox - m13 * oy - m23 * oz + nm33;
        boolean one = Math.abs(sx) == 1.0 && Math.abs(sy) == 1.0 && Math.abs(sz) == 1.0;
        dest.properties = properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
                | (one ? 0 : PROPERTY_ORTHONORMAL));
        return dest;
    }
602867
public static void scale( double alpha , DMatrixD1 a )
    {
        // on very small matrices (2 by 2) the call to getNumElements() can slow it down
        // slightly compared to other libraries since it involves an extra multiplication.
        final int size = a.getNumElements();

        for( int i = 0; i < size; i++ ) {
            a.data[i] *= alpha;
        }
    }
764335
public void setScale(final float scale) {
        if (equal(mScale, scale) != true) {
            Log.d(TAG, "setScale(): old: %.2f, new: %.2f", mScale, scale);
            mScale = scale;
            setScale(mSceneRootObject, scale);
            setScale(mMainCameraRootObject, scale);
            setScale(mLeftCameraRootObject, scale);
            setScale(mRightCameraRootObject, scale);
            for (OnScaledListener listener : mOnScaledListeners) {
                try {
                    listener.onScaled(scale);
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.e(TAG, e, "setScale()");
                }
            }
        }
    }
585747
private DataPoints scale(final DataPoints points, final double scale_factor) {
    // TODO(cl) - Using an array as the size function may not return the exact
    // results and we should figure a way to avoid copying data anyway.
    final List<DataPoint> dps = new ArrayList<DataPoint>();
    final boolean scale_is_int = (scale_factor == Math.floor(scale_factor)) && 
        !Double.isInfinite(scale_factor);
    final SeekableView view = points.iterator();
    while (view.hasNext()) {
      DataPoint pt = view.next();
      if (pt.isInteger() && scale_is_int) {
        dps.add(MutableDataPoint.ofLongValue(pt.timestamp(), 
            (long)scale_factor * pt.longValue()));
      } else {
        // NaNs are fine here, they'll just be re-computed as NaN
        dps.add(MutableDataPoint.ofDoubleValue(pt.timestamp(), 
            scale_factor * pt.toDouble()));
      }
    }
    final DataPoint[] results = new DataPoint[dps.size()];
    dps.toArray(results);
    return new PostAggregatedDataPoints(points, results);
  }