public List<FunctionPair> doMatching(TaskMonitor monitor) throws CancelledException {
		matches = new LinkedList<FunctionPair>();

		for (int round = 0; round < 2; round++) {
			monitor.checkCancelled();
			NeighborGenerator[] generatorList = buildNeighborGenerators(round);
			if (round == 0) {
				monitor.setMessage("Matching round 1...");
				monitor.initialize(seeds.size());
				for (FunctionPair bridge : seeds) {
					monitor.checkCancelled();
					monitor.incrementProgress(1);
					acceptMatch(bridge);
					PotentialPair impliedPair = analyze(bridge, generatorList);
					if (impliedPair != null) {
						implications.add(impliedPair);
					}
				}
				seeds = null;		// seeds are no longer needed, free up memory
			}
			else {
				implications.clear();
				monitor.setMessage("Matching round 2...");
				monitor.initialize(matches.size());
				for (FunctionPair bridge : matches) {
					monitor.checkCancelled();
					monitor.incrementProgress(1);
					PotentialPair impliedPair = analyze(bridge, generatorList);
					if (impliedPair != null) {
						implications.add(impliedPair);
					}
				}
			}
			monitor.setMessage("Gathering matches for round " + (round + 1) + "...");
			int maxSize = implications.size();
			monitor.initialize(maxSize + 1);
			while (true) {
				monitor.checkCancelled();
				int size = implications.size();
				if (size > maxSize) {
					maxSize = size;
					monitor.setMaximum(maxSize + 1);
				}
				monitor.setProgress((maxSize - size) + 1);
				if (size == 0) {
					break;
				}
				PotentialPair bestImplied = implications.last();
				implications.remove(bestImplied);
				FunctionPair bridge =
					bestImplied.getSource().findEdge(bestImplied.getDestination());
				if (bridge != null) {
					acceptMatch(bridge);
					PotentialPair impliedPair = analyze(bridge, generatorList);
					if (impliedPair != null) {
						implications.add(impliedPair);
					}
				}
				// Let pair that produced this new match select a new PotentialPair
				PotentialPair impliedPair = analyze(bestImplied.getOrigin(), generatorList);
				if (impliedPair != null) {
					implications.add(impliedPair);
				}
				if (implications.isEmpty() || implications.last().getScore() < impThreshold) {
					break;
				}
			}
		}

		//Hole Patching
		LinkedList<FunctionPair> matchCopy = new LinkedList<FunctionPair>(matches);
		VectorCompare veccompare = new VectorCompare();
		monitor.setMessage("Patching holes...");
		monitor.initialize(matches.size());
		for (FunctionPair bridge : matchCopy) {
			monitor.checkCancelled();
			monitor.incrementProgress(1);
			if (bridge.getSourceNode().getParents().size() == 1 &&
				bridge.getDestNode().getParents().size() == 1) {
				FunctionNode sp = bridge.getSourceNode().getParents().iterator().next();
				FunctionNode dp = bridge.getDestNode().getParents().iterator().next();
				if (sp.findEdge(dp) == null && !sp.isAcceptedMatch() && !dp.isAcceptedMatch()) {
					double similarity = sp.getVector().compare(dp.getVector(), veccompare);
					double confidence = vectorFactory.calculateSignificance(veccompare);
					FunctionPair rentBridge = new FunctionPair(sp, dp, similarity, confidence);
					acceptMatch(rentBridge);
				}
			}
		}

		return matches;
	}
Given a set of -seeds- iteratively extend the set of matches
Loop greedily picking the best relative match, maintaining score sorts and other bookkeeping
@param monitor is the TaskMonitor
@return the final list of FunctionPairs as official matches
@throws CancelledException if the user cancels the correlation
Ghidra/Features/VersionTrackingBSim/src/main/java/ghidra/feature/vt/api/BSimProgramCorrelatorMatching.java