docs: public void setInput(long seed, final double[] nums, final int numcat, final int[] cats) {
        _a = _dvec;
        Arrays.fill(_a.raw(), 0f);
  
        // random projection from fullN down to max_categorical_features
        if (params.max_categorical_features < _dinfo.fullN() - _dinfo._nums) {
          assert(nums.length == _dinfo._nums);
          final int M = nums.length + params.max_categorical_features;
          final boolean random_projection = false;
          final boolean hash_trick = true;
          if (random_projection) {
            final int N = _dinfo.fullN();
            assert (_a.size() == M);
  
            // sparse random projection
            for (int i = 0; i < M; ++i) {
              for (int c = 0; c < numcat; ++c) {
                int j = cats[c];
                Random rng = new Random(params.seed + i*N + j);
                float val = 0;
                final float rnd = rng.nextFloat();
                if (rnd < 1. / 6.) val = (float) Math.sqrt(3);
                if (rnd > 5. / 6.) val = -(float) Math.sqrt(3);
                _a.add(i, 1f * val);
              }
              Random rng = new Random(params.seed + i*N + _dinfo.numStart());
              for (int n = 0; n < nums.length; ++n) {
                float val = 0;
                final float rnd = rng.nextFloat();
                if (rnd < 1. / 6.) val = (float) Math.sqrt(3);
                if (rnd > 5. / 6.) val = -(float) Math.sqrt(3);
                _a.set(i, (Double.isNaN(nums[n]) ? 0f /*Always do MeanImputation during scoring*/ : (float) nums[n]) * val);
              }
            }
          } else if (hash_trick) {
            // Use hash trick for categorical features
            assert (_a.size() == M);
            // hash N-nums.length down to M-nums.length = cM (#categorical slots - always use all numerical features)
            final int cM = params.max_categorical_features;
  
            assert (_a.size() == M);
            Hash murmur = MurmurHash.getInstance();
            for (int i = 0; i < numcat; ++i) {
              ByteBuffer buf = ByteBuffer.allocate(4);
              int hashval = murmur.hash(buf.putInt(cats[i]).array(), 4, (int)params.seed); // turn horizontalized categorical integer into another integer, based on seed
  //            int hashval = cats[i] ^ (int)params.seed; // turn horizontalized categorical integer into another integer, based on seed
              _a.add(Math.abs(hashval % cM), 1f); // restrict to limited range
            }
            for (int i = 0; i < nums.length; ++i)
              _a.set(cM + i, Double.isNaN(nums[i]) ? 0f /*Always do MeanImputation during scoring*/ : (float) nums[i]);
  
          }
        } else {
          for (int i = 0; i < numcat; ++i) _a.set(cats[i], 1f); // one-hot encode categoricals
          for (int i = 0; i < nums.length; ++i)
            _a.set(_dinfo.numStart() + i, Double.isNaN(nums[i]) ? 0f /*Always do MeanImputation during scoring*/ : (float) nums[i]);
        }
  //      Log.info("Input Layer: " + ArrayUtils.toString(_a.raw()));
  
        // Input Dropout
        if (_dropout == null) return;
        seed += params.seed + 0x1337B4BE;
        _dropout.randomlySparsifyActivation(_a, seed);
  
        if (params.sparse) {
          _svec = new SparseVector(_dvec);
          _a = _svec;
        }
      }