public void train(int maxIter, int windowSize, double initStep, double shrinkage){
		int iteration = m_iteration;
		
		// Step 0: output the settings
		System.out.println("[Info]LambdaRank configuration:");
		System.out.format("\tOptimization Type %s, Lambda %.3f, Shrinkage %.3f, WindowSize %d\n", m_oType, m_lambda, shrinkage, windowSize);
		System.out.format("\tInitial step size %.1f, Steps %d, Iteration %d\n", initStep, maxIter, iteration);
		System.out.println("Iter\tMisorder\tLogLilikelihood\tPerf");
		
		// Step 1: setup the workers
		int workerSize = initWorkers(windowSize, maxIter, initStep, shrinkage);
		
		// Step 2: start multi-thread training
		double weight = 1.0 / workerSize, performance = 0;
		int querySize = m_queries.size();
		long starttimer = System.currentTimeMillis();
		double obj = 0, perf = 0;
		int misorder = 0;	
		
//		//evaluate initial performance
//		WaitTillFinish(OperationType.OT_evaluate);
//		for(LambdaRankWorker worker:m_workers){
//			obj += worker.m_obj;
//			perf += worker.m_perf;
//			misorder += worker.m_misorder;
//		}
//		perf /= querySize;
//		obj -= 0.5 * m_lambda * Utils.L2Norm(m_weight);//to be maximized		
//		System.out.format("0\t%d\t%.2f\t%.4f\n", misorder, obj, perf);
		
		for(int i=0; i<iteration; i++){
			// training operation
			WaitTillFinish(OperationType.OT_train);
			
			// aggregate the learned weights from workers
			Arrays.fill(m_weight, 0);
			for(LambdaRankWorker worker:m_workers)
				Utils.add2Array(m_weight, worker.getWeight(), weight);
			
			//evaluate training performance
			WaitTillFinish(OperationType.OT_evaluate);
			
			obj = 0; perf = 0; misorder = 0;
			for(LambdaRankWorker worker:m_workers){
				obj += worker.m_obj;
				perf += worker.m_perf;
				misorder += worker.m_misorder;
			}
			perf /= querySize;
			obj -= 0.5 * m_lambda * Utils.L2Norm(m_weight);//to be maximized
			
			if (performance>0){
				if (performance<=perf)//become better
					iteration--;
				else//become worse
					iteration = Math.min(MAX_TRAIN_ITER, iteration+2);
			}
			performance = perf;
			
			System.out.format("%d\t%d\t%.2f\t%.4f\n", 1+i, misorder, obj, perf);
		}

		System.out.format("[Info]Training procedure takes %.2f seconds to finish...\n", (System.currentTimeMillis()-starttimer)/1000.0);
	}