public static void main(final String[] args) throws Exception {
		// Start timing
		final long t = System.currentTimeMillis();

		// check arguments
		if (args.length != 3 && args.length != 4)
			usage();

		// Initialize middleware
		Comm.init (args);
		final Comm world = Comm.world();		

		// load data
		Resources.loadFromFile(args[0], args[1], args[2]);

		// intitiate the algorithm
		final SimulatedAnnealing sa = new SimulatedAnnealing();

		// get distributed of iteration
		final int interations = (int)Math.ceil((double)sa.getPerturbInteration()/(double)world.size());

		// schedule transmit buffer
		final ObjectItemBuf<Schedule> buf = ObjectItemBuf.buffer();

		// loop until freezing temperature is reached
		while(!sa.isDone()) {
			// run iterations
			sa.runIteration(interations);

			// reduce
			buf.item = sa.getBest();
			world.allReduce(0, buf, Schedule.REDUCE_OP);
			sa.setBest(buf.item);
		}

		// if it is node 0
		if(world.rank() == 0) {
			// save result to file
			final Schedule best = sa.getBest();
			if(args.length == 4) {
				final File outputfile = new File(args[3]);
				outputfile.createNewFile();
				final PrintStream ps = new PrintStream(outputfile);
				ps.println(best);
				ps.flush();
				ps.close();
			}

			// print out timing and stats
			final int[] counters = best.getCounters();
			System.out.println("" + (System.currentTimeMillis()-t) + "\t" + best.getRank() + "\t"
					+ counters[Schedule.SE_COUNTER] + "\t"
					+ counters[Schedule.CE_COUNTER] + "\t"
					+ counters[Schedule.ME_COUNTER] + "\t"
					+ counters[Schedule.FE_COUNTER]);
		}
	}