docs: private static DataSet loadG(Reader reader, double sparseRatio, int vectorLength, boolean classification, DataStore store) throws IOException
      {
          StringBuilder processBuffer = new StringBuilder(20);
          StringBuilder charBuffer = new StringBuilder(1024);
          char[] buffer = new char[1024];
          DataStore sparceVecs = store.emptyClone();
          sparceVecs.setCategoricalDataInfo(new CategoricalData[0]);
          /**
           * The category "label" for each value loaded in
           */
          List<Double> labelVals = new DoubleList();
          Map<Double, Integer> possibleCats = new HashMap<>();
          int maxLen= 1;
          
          STATE state = STATE.INITIAL;
          int position = 0;
          SparseVector tempVec = new SparseVector(1, 1);
          /**
           * The index that we have parse out of a non zero pair
           */
          int indexProcessing = -1;
          while(true)
          {
              
              while(charBuffer.length()-position <= 1)//make sure we have chars to handle
              {
                  //move everything to the front
                  charBuffer.delete(0, position);
                  position = 0;
                  
                  int read = reader.read(buffer);
                  if(read < 0)
                      break;
                  charBuffer.append(buffer, 0, read);
              }
              
              if(charBuffer.length()-position == 0)//EOF, no more chars
              {
                  if(state == STATE.LABEL)//last line was empty
                  {
                      double label = Double.parseDouble(processBuffer.toString());
  
                      if (!possibleCats.containsKey(label) && classification)
                          possibleCats.put(label, possibleCats.size());
                      labelVals.add(label);
                      
                      sparceVecs.addDataPoint(new DataPoint(new SparseVector(maxLen, 0)));
                  }
                  else if(state == STATE.WHITESPACE_AFTER_LABEL)//last line was empty, but we have already eaten the label
                  {
                      sparceVecs.addDataPoint(new DataPoint(new SparseVector(maxLen, 0)));
                  }
                  else if(state == STATE.FEATURE_VALUE || state == STATE.WHITESPACE_AFTER_FEATURE)//line ended after a value pair
                  {
                      //process the last value pair & insert into vec
                      double value = StringUtils.parseDouble(processBuffer, 0, processBuffer.length());
                      processBuffer.delete(0, processBuffer.length());
  
                      maxLen = Math.max(maxLen, indexProcessing+1);
                      tempVec.setLength(maxLen);
                      if (value != 0)
                          tempVec.set(indexProcessing, value);
                      sparceVecs.addDataPoint(new DataPoint(tempVec.clone()));
                  }
                  else if(state == STATE.NEWLINE)
                  {
                      //nothing to do and everything already processed, just return
                      break;
                  }
                  else
                      throw new RuntimeException();
                  //we may have ended on a line, and have a sparse vec to add before returning
                  break;
              }
              
              char ch = charBuffer.charAt(position);
              switch(state)
              {
                  case INITIAL:
                      state = STATE.LABEL;
                      break;
                  case LABEL:
                      if (Character.isDigit(ch)  || ch == '.' || ch == 'E' || ch == 'e' || ch == '-' || ch == '+')
                      {
                          processBuffer.append(ch);
                          position++;
                      }
                      else if (Character.isWhitespace(ch))//this gets spaces and new lines
                      {
                          double label = Double.parseDouble(processBuffer.toString());
  
                          if (!possibleCats.containsKey(label) && classification)
                              possibleCats.put(label, possibleCats.size());
                          labelVals.add(label);
  
                          //clean up and move to new state
                          processBuffer.delete(0, processBuffer.length());
                          
                          if (ch == '\n' || ch == '\r')//empty line, so add a zero vector
                          {
                              tempVec.zeroOut();
                              sparceVecs.addDataPoint(new DataPoint(new SparseVector(maxLen, 0)));
                              state = STATE.NEWLINE;
                          }
                          else//just white space
                          {
                              tempVec.zeroOut();
                              state = STATE.WHITESPACE_AFTER_LABEL;
                          }
                      }
                      else
                          throw new RuntimeException("Invalid LIBSVM file");
                      break;
                  case WHITESPACE_AFTER_LABEL:
                      if (Character.isDigit(ch))//move to next state
                      {
                          state = STATE.FEATURE_INDEX;
                      }
                      else if (Character.isWhitespace(ch))
                      {
                          if (ch == '\n' || ch == '\r')
                          {
                              tempVec.zeroOut();
                              sparceVecs.addDataPoint(new DataPoint(new SparseVector(maxLen, 0)));///no features again, add zero vec
                              state = STATE.NEWLINE;
                          }
                          else//normal whie space
                              position++;
                      }
                      else
                          throw new RuntimeException();
                      break;
                  case FEATURE_INDEX:
                      if (Character.isDigit(ch))
                      {
                          processBuffer.append(ch);
                          position++;
                      }
                      else if(ch == ':')
                      {
                          indexProcessing = StringUtils.parseInt(processBuffer, 0, processBuffer.length())-1;
                          processBuffer.delete(0, processBuffer.length());
                          
                          
                          state = STATE.FEATURE_VALUE;
                          position++;
                      }
                      else
                          throw new RuntimeException();
                      break;
                  case FEATURE_VALUE:
                      //we need to accept all the values that may be part of a float value
                      if (Character.isDigit(ch) || ch == '.' || ch == 'E' || ch == 'e' || ch == '-' || ch == '+')
                      {
                          processBuffer.append(ch);
                          position++;
                      }
                      else
                      {
                          double value = StringUtils.parseDouble(processBuffer, 0, processBuffer.length());
                          processBuffer.delete(0, processBuffer.length());
     
                          maxLen = Math.max(maxLen, indexProcessing+1);
                          tempVec.setLength(maxLen);
                          if (value != 0)
                              tempVec.set(indexProcessing, value);
                          
                          if (Character.isWhitespace(ch))
                              state = STATE.WHITESPACE_AFTER_FEATURE;
                          else
                              throw new RuntimeException();
                      }
                      
                      break;
                  case WHITESPACE_AFTER_FEATURE:
                      if (Character.isDigit(ch))
                          state = STATE.FEATURE_INDEX;
                      else if (Character.isWhitespace(ch))
                      {
                          if (ch == '\n' || ch == '\r')
                          {
                              sparceVecs.addDataPoint(new DataPoint(tempVec.clone()));
                              tempVec.zeroOut();
                              state = STATE.NEWLINE;
                          }
                          else
                              position++;
                      }
                      break;
                  case NEWLINE:
                      if (ch == '\n' || ch == '\r')
                          position++;
                      else
                      {
                          state = STATE.LABEL;
                      }
                      break;
              }
          }
          
          if (vectorLength > 0)
              if (maxLen > vectorLength)
                  throw new RuntimeException("Length given was " + vectorLength + ", but observed length was " + maxLen);
              else
                  maxLen = vectorLength;
  
          if(classification)
          {
              CategoricalData predicting = new CategoricalData(possibleCats.size());
  
              //Give categories a unique ordering to avoid loading issues based on the order categories are presented
              List<Double> allCatKeys = new DoubleList(possibleCats.keySet());
              Collections.sort(allCatKeys);
              for(int i = 0; i < allCatKeys.size(); i++)
                  possibleCats.put(allCatKeys.get(i), i);
              //apply to target values now 
              
              IntList label_targets = IntList.view(labelVals.stream()
                      .mapToInt(possibleCats::get)
                      .toArray());
  
              sparceVecs.setNumNumeric(maxLen);
              sparceVecs.finishAdding();
              ClassificationDataSet cds = new ClassificationDataSet(sparceVecs, label_targets);
  
              if(store instanceof RowMajorStore)
                  cds.applyTransform(new DenseSparceTransform(sparseRatio));
  
              return cds;
          }
          else//regression
          {
              sparceVecs.setNumNumeric(maxLen);
              sparceVecs.finishAdding();
              RegressionDataSet rds = new RegressionDataSet(sparceVecs, labelVals);
              rds.applyTransform(new DenseSparceTransform(sparseRatio));
  
              return rds;
          }
      }