private CostMatrixBuilder[] createConnectionCostFile(String connectionCSVFilename, String connectionCostDataFilename, short defaultCost, String charset) throws IOException {

		CostMatrixBuilder[] matrixBuilders = new CostMatrixBuilder[3];

		matrixBuilders[0] = new CostMatrixBuilder();
		matrixBuilders[1] = new CostMatrixBuilder();
		matrixBuilders[2] = new CostMatrixBuilder();
		Vector<String> rule1 = new Vector<String>();
		Vector<String> rule2 = new Vector<String>();
		Vector<String> rule3 = new Vector<String>();

		// The approximate length of the file, plus a bit. If we're wrong it'll be expanded during processing
		short[] scores = new short[30000];

		// Read connection cost CSV data
		CSVParser parser = new CSVParser(new FileInputStream(connectionCSVFilename), charset);
		String t[];
		int line = 0;
		while ((t = parser.nextTokens()) != null) {
			if (t.length < 4) {
				throw new IOException("Connection cost CSV format error");
			}
			matrixBuilders[0].add(t[0]);
			rule1.add(t[0]);

			matrixBuilders[1].add(t[1]);
			rule2.add(t[1]);

			matrixBuilders[2].add(t[2]);
			rule3.add(t[2]);

			if (line == scores.length) {
				scores = resize(scores);
			}

			scores[line++] = (short) Integer.parseInt(t[3]);
		}

		// Compile CostMatrixBuilders
		matrixBuilders[0].build();
		matrixBuilders[1].build();
		matrixBuilders[2].build();

		int size1 = matrixBuilders[0].size();
		int size2 = matrixBuilders[1].size();
		int size3 = matrixBuilders[2].size();
		int ruleSize = rule1.size();


		// Write connection cost data
		MappedByteBuffer buffer = null;
		ShortBuffer shortBuffer = null;
		int matrixSizeBytes = (size1 * size2 * size3 * 2);
		int headerSizeBytes = (3 * 2);

		RandomAccessFile file = new RandomAccessFile(connectionCostDataFilename, "rw");
		file.setLength(0);
		file.writeShort(size1);
		file.writeShort(size2);
		file.writeShort(size3);
		file.setLength(headerSizeBytes + matrixSizeBytes);
		FileChannel indexChannel = file.getChannel();
		buffer = indexChannel.map(FileChannel.MapMode.READ_WRITE, headerSizeBytes, matrixSizeBytes);
		shortBuffer = buffer.asShortBuffer();
		indexChannel.close();

		for (int i = 0; i < (size1 * size2 * size3); i++) {
			shortBuffer.put(i, defaultCost);
		}

		for (int i = 0; i < ruleSize; i++) {
			Vector<Integer> r1 = matrixBuilders[0].getRuleIdList(rule1.get(i));
			Vector<Integer> r2 = matrixBuilders[1].getRuleIdList(rule2.get(i));
			Vector<Integer> r3 = matrixBuilders[2].getRuleIdList(rule3.get(i));

			for (Iterator<Integer> i1 = r1.iterator(); i1.hasNext();) {
				int ii1 = i1.next();
				for (Iterator<Integer> i2 = r2.iterator(); i2.hasNext();) {
					int ii2 = i2.next();
					for (Iterator<Integer> i3 = r3.iterator(); i3.hasNext();) {
						int ii3 = i3.next();
						int position = size3 * (size2 * ii1 + ii2) + ii3;
						shortBuffer.put(position, scores[i]);
					}
				}
			}
		}

		buffer.force();

		return matrixBuilders;

	}