@Override
	public void run(TaskMonitor monitor) throws CancelledException {
		monitor.setIndeterminate(true);
		monitor.setMessage("Gathering function entries and interiors");

		//get all the function entries and interiors that are consistent
		//with the requirements in params
		params.computeFuncEntriesAndInteriors(monitor);
		AddressSet allEntries = params.getFuncEntries();
		AddressSet allInteriors = params.getFuncInteriors();

		//defined data in executable sections will be added to the test set
		AddressSet definedData = ModelTrainingUtils.getDefinedData(program, monitor);

		for (Integer factor : params.getSamplingFactors()) {
			//get the addresses used for training and testing
			TrainingAndTestData data =
				getTrainingAndTestData(allEntries, allInteriors, definedData, factor, monitor);
			if (data == null) {
				continue;
			}
			data.reduceTestSetSize(testSetMax, monitor);
			monitor.setIndeterminate(false);
			for (Integer preBytes : params.getPreBytes()) {
				for (Integer initialBytes : params.getInitialBytes()) {
					Msg.info(this,
						String.format(
							"Data Gathering Parameters: factor: %d preBytes: %s initialBytes: %d",
							factor, preBytes, initialBytes));

					//create the vectors for the training addresses
					List<Example<Label>> trainingData = new ArrayList<>();
					monitor.setMessage("Generating vectors for function entries");
					trainingData.addAll(ModelTrainingUtils.getVectorsFromAddresses(program,
						data.getTrainingPositive(), RandomForestFunctionFinderPlugin.FUNC_START,
						preBytes, initialBytes, params.getIncludeBitFeatures(), monitor));
					monitor.setMessage("Generating vectors for function interiors");
					trainingData.addAll(ModelTrainingUtils.getVectorsFromAddresses(program,
						data.getTrainingNegative(), RandomForestFunctionFinderPlugin.NON_START,
						preBytes, initialBytes, params.getIncludeBitFeatures(), monitor));

					//should only happen with very small training sets where MemoryAccessExceptions
					//were thrown during vector generation
					if (trainingData.isEmpty()) {
						Msg.showWarn(this, null, "Empty Training Set", String.format(
							"No vectors were generated for supplied addresses.  preBytes = %d, " +
								"initialBytes = %d",
							preBytes, initialBytes));
						continue;
					}

					//train the model
					EnsembleModel<Label> randomForest = trainModel(trainingData, monitor);

					//evaluate the model and create a RandomForestRowObject
					AddressSet errors = new AddressSet();
					int[] confusionMatrix = evaluateModel(randomForest, data.getTestPositive(),
						data.getTestNegative(), errors, preBytes, initialBytes, monitor);
					if (!monitor.isCancelled()) {
						RandomForestRowObject row = new RandomForestRowObject(preBytes,
							initialBytes, factor, confusionMatrix, randomForest, errors,
							data.getTrainingPositive(), params.getIncludeBitFeatures());
						row.setContextRegistersAndValues(params.getContextRegisterNames(),
							params.getContextRegisterVals());
						rowObjectConsumer.accept(row);
					}
				}
			}
		}
	}
Adds a {@ProgramSelection} to the training set. Function starts within the selection are
added as positive examples and everything else is added as a negative example.

<p>
Addresses which are not aligned or which do not agree with the context register values
in the {@code params} variable of the constructor are ignored.
@param selection selection to add
@return number of aligned addresses conflicting with the context register data specified in
{@code params}
Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestTrainingTask.java