TrainingAndTestData getTrainingAndTestData(AddressSet allEntries, AddressSet allInteriors,
			AddressSet definedData, int factor, TaskMonitor monitor) throws CancelledException {
		//if the user has specified addresses to use in training,
		//don't allow those addresses to also be selected at random
		AddressSet selectableEntries = allEntries.subtract(additionalStarts);
		AddressSet selectableInteriors = allInteriors.subtract(additionalNonStarts);
		AddressSet trainingPositive = new AddressSet(additionalStarts);
		AddressSet trainingNegative = new AddressSet(additionalNonStarts);

		//select function entries at random and add them to the training set
		long numEntries =
			(int) Math.min(params.getMaxStarts(), selectableEntries.getNumAddresses());
		monitor.setIndeterminate(true);
		monitor.setMessage("Selecting " + numEntries + " random function entries");
		long start = System.nanoTime();
		AddressSetView randomFuncEntries =
			RandomSubsetUtils.randomSubset(selectableEntries, numEntries, monitor);
		long end = System.nanoTime();
		Msg.info(this, String.format("factor: %d elapsed selecting random entries: %g", factor,
			(end - start) / NANOSECONDS_PER_SECOND));
		trainingPositive = trainingPositive.union(randomFuncEntries);
		if (trainingPositive.isEmpty()) {
			Msg.showError(this, null, "Data Gathering Error", "No functions in training set");
			return null;
		}
		//function entries that weren't selected are used for testing
		AddressSet testPositive = selectableEntries.subtract(randomFuncEntries);
		if (testPositive.isEmpty()) {
			Msg.showWarn(this, null, "Test Set Warning",
				"No function entries in test set for models with sampling factor " + factor);
		}
		//for the randomly-selected function entries, optionally add the immediately 
		//preceding and following code units to the training and test sets as negative examples
		AddressSet immediatelyPrecedingTraining = new AddressSet();
		AddressSet immediatelyFollowingTraining = new AddressSet();
		AddressSet immediatelyPrecedingTest = new AddressSet();
		AddressSet immediatelyFollowingTest = new AddressSet();
		if (params.getIncludePrecedingAndFollowing()) {
			immediatelyPrecedingTraining =
				ModelTrainingUtils.getPrecedingAddresses(program, randomFuncEntries, monitor);
			immediatelyFollowingTraining =
				ModelTrainingUtils.getFollowingAddresses(program, randomFuncEntries, monitor);
			immediatelyPrecedingTest =
				ModelTrainingUtils.getPrecedingAddresses(program, testPositive, monitor);
			immediatelyFollowingTest =
				ModelTrainingUtils.getFollowingAddresses(program, testPositive, monitor);
			//immediatelyPreceding and immediately following can intersect in
			//certain cases; subtract the overlap
			AddressSet before = immediatelyPrecedingTraining.union(immediatelyPrecedingTest);
			AddressSet after = immediatelyFollowingTraining.union(immediatelyFollowingTest);
			immediatelyPrecedingTraining = immediatelyPrecedingTraining.subtract(after);
			immediatelyPrecedingTest = immediatelyPrecedingTest.subtract(after);
			immediatelyFollowingTraining = immediatelyFollowingTraining.subtract(before);
			immediatelyFollowingTest = immediatelyFollowingTest.subtract(before);
			//Since immediatelyFollowingXand immediatelyPrecedingX are explicitly
			//added to the training/test sets, remove them from the set of interiors which could be
			//randomly selected for inclusion in the training set
			selectableInteriors = selectableInteriors
					.subtract(immediatelyFollowingTraining.union(immediatelyPrecedingTraining));
			selectableInteriors = selectableInteriors
					.subtract(immediatelyFollowingTest.union(immediatelyPrecedingTest));
			//remove before and after from definedData
			definedData = definedData.subtract(before.union(after));
		}
		trainingNegative = trainingNegative
				.union(immediatelyPrecedingTraining.union(immediatelyFollowingTraining));

		//now select random function interiors and add them to training set 
		monitor.setMessage(
			"Selecting " + numEntries * factor + " random addresses within function interiors");
		start = System.nanoTime();
		long numInteriors = numEntries * factor;

		AddressSetView randomFuncInteriors = numInteriors < selectableInteriors.getNumAddresses()
				? RandomSubsetUtils.randomSubset(selectableInteriors, numInteriors, monitor)
				: selectableInteriors;
		end = System.nanoTime();
		Msg.info(this, String.format("factor: %d elapsed selecting random interiors: %g seconds",
			factor, (end - start) / NANOSECONDS_PER_SECOND));
		trainingNegative = trainingNegative.union(randomFuncInteriors);
		if (trainingNegative.isEmpty()) {
			Msg.showError(this, null, "Data Gathering Error",
				"No non-starts in training set for sampling factor " + factor);
			return null;
		}
		if (trainingPositive.intersects(trainingNegative)) {
			Address first = trainingPositive.findFirstAddressInCommon(trainingNegative);
			Msg.showWarn(this, null, "Overlap between Training Positive and Training Negative Sets",
				"Example: " + first.toString());
		}
		AddressSet unusedInteriors = selectableInteriors.subtract(randomFuncInteriors);
		AddressSet testNegative = unusedInteriors.union(definedData);
		testNegative = testNegative.union(immediatelyPrecedingTest).union(immediatelyFollowingTest);
		if (testNegative.isEmpty()) {
			Msg.showWarn(this, null, "Test Set Warning",
				"No function interiors in test set for models with sampling factor " + factor);
		}
		if (testPositive.intersects(testNegative)) {
			Address first = testPositive.findFirstAddressInCommon(testNegative);
			Msg.showWarn(this, null, "Overlapping Test Positive and Negative sets",
				"Example: " + first.toString());
		}
		if ((trainingPositive.union(trainingNegative)
				.intersects(testPositive.union(testNegative)))) {
			Address first = trainingPositive.union(trainingNegative)
					.findFirstAddressInCommon(testPositive.union(testNegative));
			Msg.showWarn(this, null, "Overlapping Training and Test Sets",
				"Example: " + first.toString());
		}
		return new TrainingAndTestData(trainingPositive, trainingNegative, testPositive,
			testNegative);
	}
Creates the training and test sets
@param allEntries function entries
@param allInteriors function interiors
@param definedData defined data
@param factor sampling factor
@param monitor task monitor
@return training and test sets
@throws CancelledException if monitor is canceled
Ghidra/Extensions/MachineLearning/src/main/java/ghidra/machinelearning/functionfinding/RandomForestTrainingTask.java