// Path: src/OpenSourceExtensions/UnorderedPair.java
// public final class UnorderedPair<E extends Comparable<E>> implements Comparable<UnorderedPair<E>> {
// 	private final E first;
// 	private final E second;
// 	
// 	/**
// 	 * Creates an unordered pair of the specified elements. The order of the arguments is irrelevant,
// 	 * so the first argument is not guaranteed to be returned by {@link #getFirst()}, for example.
// 	 * @param a one element of the pair. Must not be <tt>null</tt>.
// 	 * @param b one element of the pair. Must not be <tt>null</tt>. May be the same as <tt>a</tt>.
// 	 */
// 	public UnorderedPair(E a, E b) {
// 		if (a.compareTo(b) < 0) {
// 			this.first = a;
// 			this.second = b;
// 		} else {
// 			this.first = b;
// 			this.second = a;
// 		}
// 	}
// 	
// 	/**
// 	 * Gets the smallest element of the pair (according to its {@link Comparable} implementation).
// 	 * @return an element of the pair. <tt>null</tt> is never returned.
// 	 */
// 	public E getFirst() {
// 		return first;
// 	}
// 	
// 	/**
// 	 * Gets the largest element of the pair (according to its {@link Comparable} implementation).
// 	 * @return an element of the pair. <tt>null</tt> is never returned.
// 	 */
// 	public E getSecond() {
// 		return second;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return 31 * first.hashCode() + 173 * second.hashCode();
// 	}
// 
// 	@Override
// 	public boolean equals(Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (getClass() != obj.getClass())
// 			return false;
// 		UnorderedPair<?> other = (UnorderedPair<?>) obj;
// 		if (!first.equals(other.first))
// 			return false;
// 		if (!second.equals(other.second))
// 			return false;
// 		return true;
// 	}
// 	
// 	public int compareTo(UnorderedPair<E> o) {
// 		int firstCmp = first.compareTo(o.first);
// 		if (firstCmp != 0)
// 			return firstCmp;
// 		return second.compareTo(o.second);
// 	}
// 	
// 	@Override
// 	public String toString() {
// 		return "(" + first + "," + second + ")";
// 	}
// }


import gnu.trove.list.array.TDoubleArrayList;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import OpenSourceExtensions.UnorderedPair;
	 * Return the proportion of times each of the attributes were used (count over total number of splits) 
	 * during the construction of the sum-of-trees by Gibbs sample.
	 * 
	 * @param type	Either "splits" or "trees" ("splits" means total number and "trees" means sum of binary values of whether or not it has appeared in the tree)
	 * @return		The proportion of splits for all Gibbs samples further indexed by the attribute 1, ..., p
	 */
	public double[] getAttributeProps(final String type) {
		int[][] variable_counts_all_gibbs = getCountsForAllAttribute(type);
		double[] attribute_counts = new double[p];
		for (int g = 0; g < num_gibbs_total_iterations - num_gibbs_burn_in; g++){
			attribute_counts = Tools.add_arrays(attribute_counts, variable_counts_all_gibbs[g]);
		}
		Tools.normalize_array(attribute_counts); //will turn it into proportions
		return attribute_counts;
	}
	
	/**
	 * For all Gibbs samples after burn in, calculate the set of interaction counts (consider a split on x_j 
	 * and a daughter node splits on x_k and that would be considered an "interaction")
	 * 
	 * @return	A matrix of size p x p where the row is top split and the column is a bottom split. It is recommended to triangularize the matrix after ignoring the order.
	 */
	public int[][] getInteractionCounts(){
		int[][] interaction_count_matrix = new int[p][p];
		
		for (int g = 0; g < gibbs_samples_of_bart_trees_after_burn_in.length; g++){
			bartMachineTreeNode[] trees = gibbs_samples_of_bart_trees_after_burn_in[g];
			
			for (bartMachineTreeNode tree : trees){
				//get the set of pairs of interactions
// Path: src/OpenSourceExtensions/UnorderedPair.java
// public final class UnorderedPair<E extends Comparable<E>> implements Comparable<UnorderedPair<E>> {
// 	private final E first;
// 	private final E second;
// 	
// 	/**
// 	 * Creates an unordered pair of the specified elements. The order of the arguments is irrelevant,
// 	 * so the first argument is not guaranteed to be returned by {@link #getFirst()}, for example.
// 	 * @param a one element of the pair. Must not be <tt>null</tt>.
// 	 * @param b one element of the pair. Must not be <tt>null</tt>. May be the same as <tt>a</tt>.
// 	 */
// 	public UnorderedPair(E a, E b) {
// 		if (a.compareTo(b) < 0) {
// 			this.first = a;
// 			this.second = b;
// 		} else {
// 			this.first = b;
// 			this.second = a;
// 		}
// 	}
// 	
// 	/**
// 	 * Gets the smallest element of the pair (according to its {@link Comparable} implementation).
// 	 * @return an element of the pair. <tt>null</tt> is never returned.
// 	 */
// 	public E getFirst() {
// 		return first;
// 	}
// 	
// 	/**
// 	 * Gets the largest element of the pair (according to its {@link Comparable} implementation).
// 	 * @return an element of the pair. <tt>null</tt> is never returned.
// 	 */
// 	public E getSecond() {
// 		return second;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		return 31 * first.hashCode() + 173 * second.hashCode();
// 	}
// 
// 	@Override
// 	public boolean equals(Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (getClass() != obj.getClass())
// 			return false;
// 		UnorderedPair<?> other = (UnorderedPair<?>) obj;
// 		if (!first.equals(other.first))
// 			return false;
// 		if (!second.equals(other.second))
// 			return false;
// 		return true;
// 	}
// 	
// 	public int compareTo(UnorderedPair<E> o) {
// 		int firstCmp = first.compareTo(o.first);
// 		if (firstCmp != 0)
// 			return firstCmp;
// 		return second.compareTo(o.second);
// 	}
// 	
// 	@Override
// 	public String toString() {
// 		return "(" + first + "," + second + ")";
// 	}
// }


// Path: src/bartMachine/bartMachineRegressionMultThread.java
import gnu.trove.list.array.TDoubleArrayList;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import OpenSourceExtensions.UnorderedPair;

	 * Return the proportion of times each of the attributes were used (count over total number of splits) 
	 * during the construction of the sum-of-trees by Gibbs sample.
	 * 
	 * @param type	Either "splits" or "trees" ("splits" means total number and "trees" means sum of binary values of whether or not it has appeared in the tree)
	 * @return		The proportion of splits for all Gibbs samples further indexed by the attribute 1, ..., p
	 */
	public double[] getAttributeProps(final String type) {
		int[][] variable_counts_all_gibbs = getCountsForAllAttribute(type);
		double[] attribute_counts = new double[p];
		for (int g = 0; g < num_gibbs_total_iterations - num_gibbs_burn_in; g++){
			attribute_counts = Tools.add_arrays(attribute_counts, variable_counts_all_gibbs[g]);
		}
		Tools.normalize_array(attribute_counts); //will turn it into proportions
		return attribute_counts;
	}
	
	/**
	 * For all Gibbs samples after burn in, calculate the set of interaction counts (consider a split on x_j 
	 * and a daughter node splits on x_k and that would be considered an "interaction")
	 * 
	 * @return	A matrix of size p x p where the row is top split and the column is a bottom split. It is recommended to triangularize the matrix after ignoring the order.
	 */
	public int[][] getInteractionCounts(){
		int[][] interaction_count_matrix = new int[p][p];
		
		for (int g = 0; g < gibbs_samples_of_bart_trees_after_burn_in.length; g++){
			bartMachineTreeNode[] trees = gibbs_samples_of_bart_trees_after_burn_in[g];
			
			for (bartMachineTreeNode tree : trees){
				//get the set of pairs of interactions
				HashSet<UnorderedPair<Integer>> set_of_interaction_pairs = new HashSet<UnorderedPair<Integer>>(p * p);