public LinearModel train(final List<String> seqs, final List<Double> vals, int k, Random random,
			double terminationEpsilon, File saveIntermediariesTo, int nThreads){
		if(seqs.size() != vals.size()){
			throw new RuntimeException("Sequences list and values list must be of the same size.");
		}
		//redirect stdout to stderr
		PrintStream sout = System.out;
		System.setOut(System.err);
		nThreads = nThreads > 0 ? nThreads : Runtime.getRuntime().availableProcessors();
		
		try{
			ExecutorService exec = Executors.newFixedThreadPool(nThreads);

			if(verbose){
				System.err.println("Running with "+nThreads+" threads.");
				System.err.println("Extracting sequence features.");
			}
			final List<FeaturesValue> shuffle = new ArrayList<FeaturesValue>();
			List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
			for( int i = 0 ; i < seqs.size() ; ++i ){
				final int index = i;
				tasks.add(new Callable<Object>(){

					@Override
					public Object call() throws Exception {
						FeaturesValue feature = new FeaturesValue(builder, seqs.get(index), vals.get(index));
						synchronized(shuffle){
							shuffle.add(feature);
						}
						return null;
					}

				});
			}
			try {
				exec.invokeAll(tasks);
			} catch (InterruptedException e) {
				//bad things
				throw new Error(e);
			}
			Collections.shuffle(shuffle, random);

			//build the cross-validation sets
			if(verbose){
				System.err.println("Building cross validation sets.");
			}
			List<CrossValidationSet> crossValSets = this.buildCrossValidationSets(k,shuffle);

			//grid search the parameters in parallel
			if(verbose){
				System.err.println("Grid searching parameters.");
			}
			GridSearch search = new GridSearchParallel(eps, cs, terminationEpsilon, crossValSets,
					builder, nThreads);
			svm_parameter param = search.search(saveIntermediariesTo);

			//build a model using the best parameters and all the given data
			if(verbose){
				System.err.println("Generating model with parameters: ");
				System.err.println("Epsilon = "+param.p);
				System.err.println("C = "+param.C);
			}
			svm_problem prob = new svm_problem();
			prob.l = seqs.size();
			prob.y = asArray(vals);
			prob.x = generateFeatures(builder, seqs);
			svm_model model = svm.svm_train(prob, param);

			return new SeqSVMModel(builder, model);
		}finally{
			//restore system.out
			System.setOut(sout);
		}
		
	}