public void train(Vector labelset, Matrix dataset) throws TrainingException {
    if (labelset.size() != dataset.columnSize()) {
      throw new CardinalityException(labelset.size(), dataset.columnSize());
    }
    
    boolean converged = false;
    int iteration = 0;
    while (!converged) {
      if (iteration > 1000) {
        throw new TrainingException("Too many iterations needed to find hyperplane.");
      }
      
      converged = true;
      int columnCount = dataset.columnSize();
      for (int i = 0; i < columnCount; i++) {
        Vector dataPoint = dataset.viewColumn(i);
        log.debug("Training point: {}", dataPoint);
        
        synchronized (this.model) {
          boolean prediction = model.classify(dataPoint);
          double label = labelset.get(i);
          if (label <= 0 && prediction || label > 0 && !prediction) {
            log.debug("updating");
            converged = false;
            update(label, dataPoint, this.model);
          }
        }
      }
      iteration++;
    }
  }