@Override
	public MultiLabelOutput inferenceProcedure(Instance instance)
			throws Exception {

		Instance tempInstance = DataUtils.createInstance(instance,
				instance.weight(), instance.toDoubleArray());
		
		Comparator<LabelCombinationExtended> probabilityComparator = new Comparator<LabelCombinationExtended>() {

			public int compare(LabelCombinationExtended left, LabelCombinationExtended right) {
				double probabilityLeft = left.getP();
				double probabilityRight = right.getP();

				if (probabilityLeft > probabilityRight) {
					return -1;
				} else if (probabilityRight > probabilityLeft) {
					return +1;
				} else { // equal
					return 0;
				}

			}
		};

		PriorityQueue<LabelCombinationExtended> queue = new PriorityQueue<LabelCombinationExtended>(
				this.numLabels, probabilityComparator);
		queue.add(new LabelCombinationExtended(this.numLabels, tempInstance, this));

		PriorityQueue<LabelCombinationExtended> unsurvived = new PriorityQueue<LabelCombinationExtended>(
				this.numLabels, probabilityComparator);

		// double max = minMode;
		LabelCombinationExtended best = null;

		while (!queue.isEmpty()) {

			LabelCombinationExtended current = queue.poll();

			best = current;
			if (best.getCurrentLabel() == this.numLabels) {
				unsurvived.clear(); // the optimal solution has been found
				break;
			}

			Instance currentInstance = current.getInstance();
			
			int i = current.getCurrentLabel();
			
			double p = this.ensemble[i].distributionForInstance(currentInstance)[1];

			LabelCombinationExtended left = new LabelCombinationExtended(current);
			left.setNextLabel(0, 1 - p);
			boolean leftAdded = addToQueue(queue, left);

			LabelCombinationExtended right = new LabelCombinationExtended(current);
			right.setNextLabel(1, p);
			boolean rightAdded = addToQueue(queue, right);

			if (!leftAdded && !rightAdded) {
				unsurvived.add(current);
			}
		}

		this.max = 0.0;
		
		while (!unsurvived.isEmpty()) { // search for approximate solution
			LabelCombinationExtended greedy = unsurvived.poll();
			if (greedy.getP() <= this.max)
				break;
			greedy = greedyApproximation(greedy, this.max);
			if (greedy.getP() > this.max) {
				best = greedy;
				max = best.getP();
			}
		}

		MultiLabelOutput result = new MultiLabelOutput(
				booleansFromDoubles(best.getCombination())); 

		return result;
	}