// SFCMain2026.cpp

#include <iostream>
#include <sstream>
//#include <fstream>
//#include <vector>
//#include <map>
//#include <ctime>
//#include <algorithm> 

#include "IO.h"
#include "GrayCode.h"
#include"MeasureOfSimilarity.h"
#include "Intervals.h"
#include "HandWrittenDigits.h"

using namespace std;
typedef unsigned int uint;

const bool check_memory = true;			// tests for memory leaks if true

void MemoryCheck();
void PrintMenu();
void Menu();

void GrayCodeExample();
void HilbertCurveExample();
void XORExample();
void IteratePointsExample();
void IterateToPointExample();
void PointBoundariesExample();			//Vestigal
void ConstructTrainingPointExample();	//Vestigal
void HandWrittenDigitsExample();
void Test();


void MemoryCheck()		// checks for memory leaks if flag is true
{
	if (check_memory)
	{
		int dbg = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
		dbg |= _CRTDBG_LEAK_CHECK_DF;
		_CrtSetDbgFlag(dbg);
	}
}

void PrintMenu()
{
	cout << "\n";
	cout << "a Gray Code Example\n";
	cout << "b Hilbert Curve Example\n";
	cout << "c XOR Example\n";
	cout << "d Iterate Points Example\n";
	cout << "e Iterate To Point Example\n";
	//cout << "f Point Boundaries Example\n";
	//cout << "g Construct Training Point Example\n";	//Vestigal
	cout << "f Hand Written Digits Example\n";
	cout << "i Test\n";
	//cout << "j TestII\n";
	//cout << "k NOP\n";
}

void Menu()
{
	string sIn;
	do
	{
		PrintMenu();
		sIn.erase();
		cin >> sIn;

		if (sIn == "a")GrayCodeExample();
		if (sIn == "b")	HilbertCurveExample();
		if (sIn == "c")	XORExample();
		if (sIn == "d")	IteratePointsExample();
		if (sIn == "e")	IterateToPointExample();
		//if (sIn == "f")	PointBoundariesExample();			//Vestigal
		//if (sIn == "g")	ConstructTrainingPointExample();	//Vestigal
		if (sIn == "f")	HandWrittenDigitsExample();
		if (sIn == "i")	Test();
		//if (sIn == "j")	TestII();

		cin.clear();
	} while (sIn == "a" || sIn == "b" || sIn == "c" || sIn == "d" || sIn == "e" || sIn == "f" || sIn == "g" || sIn == "h" || sIn == "i" || sIn == "j");
}

int main()
{
	cout << "\nSFCMain2026\n";
	srand((unsigned)time(NULL));
	MemoryCheck();
	Menu();
	return 0;
}

void GrayCodeExample()
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	//Intervals cI = Intervals();

	string sFile = "GrayCodeExample.txt";

	uint nBits = 6;
	nBits = cIO.GetEntry("Bits = ", nBits);

	ss << "\nGrayCodeExample.txt\n";
	ss << "GrayCode flips only one bit with each increment or decrement.\n";
	ss << "The Base2Sum and GraySum is the number of 1's in GrayCode.\n";
	ss << "If n is the number of bits, there are n! combinations or reorderings.\n";
	ss << "ReOrdering the Gray bits reorders the Base2 bits, the linear order, and the classification clusters.\n\n";
	ss << "Bits = " << nBits << "\n";
	ss << "Base10\tBase2\t\tGrayCode\tGraySum == Number of 1's in GrayCode\n";

	vector<bool> vStart(nBits, false);
	vector<bool> vStop(nBits, true);

	uint nSpace0 = 0;
	uint nSpace1 = 1;
	for (vector<bool> vBase2 = vStart; vBase2 <= vStop; vBase2 = cGC.IncrementBase2(vBase2))
	{
		uint nBase10 = cGC.Base2ToBase10(vBase2);
		vector<bool> vGray = cGC.Base2ToGray(vBase2);
		ss << nBase10 << "\t\t" << cIO.DumpVector(nSpace0, vBase2) << "\t\t" << cIO.DumpVector(nSpace0, vGray) << "\t\t" << cGC.GraySum(vGray) << "\n";

		if (vBase2 == vStop)
			break;
	}

	cout << "Bits = " << nBits << "\n";
	cout << ss.str() << "\n";
	cout << "\nSaved in " << sFile << "\n";

	ss << "\n" << sFile << "\n\n";
	cIO.WriteFile(sFile, ss.str());
}

void HilbertCurveExample()		//***
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();

	string sFile = "HilbertCurveExample.txt";

	uint nSpace0 = 0;
	uint nSpace1 = 1;

	uint nDimensions = 3;
	uint nBitsPerDimension = 3;
	uint nTotalBits = nDimensions * nBitsPerDimension;

	cout << "\n" << sFile << "\n";
	cout << "\nDimensions = " << nDimensions << "\n";
	cout << "\nBits Per Dimension = " << nBitsPerDimension << "\n";
	cout << "\nTotal Bits = " << nTotalBits << "\n";
	cout << "Total Length = " << pow(2, nTotalBits) << "\n";

	ss << "\n" << sFile << "\n";
	ss << "Dimensions = " << nDimensions << "\n";
	ss << "Bits Per Dimension = " << nBitsPerDimension << "\n";
	ss << "\nTotal Bits (Dimensions * Bits Per Dimension) = " << nTotalBits << "\n";
	ss << "Total Length (2^nTotalBits) = " << pow(2, nTotalBits) << "\n\n";

	ss << "nBase10\tvBase2\tvGray\tGrayCoordinates\tvBase10\n";

	vector<bool> vStart(nTotalBits, false);
	vector<bool> vStop(nTotalBits, true);

	vector<uint> vPrevBase10(nDimensions, 0);
	
	map<uint, vector<uint>> mSFC; 
	for (vector<bool> vBase2 = vStart; vBase2 <= vStop; vBase2 = cGC.IncrementBase2(vBase2))
	{
		uint nBase10                  = cGC.Base2ToBase10(vBase2);
		vector<bool> vGray            = cGC.Base2ToGray(vBase2);
		vector<bool> vGrayCoordinates = cGC.GrayCodeToGrayCoordinates(nBitsPerDimension, nDimensions, vGray);
		vector<uint> vBase10          = cGC.GrayCoordinatesToBase10Coordinates(nBitsPerDimension, nDimensions, vGrayCoordinates);

		vector<bool> vGrayCheck = cGC.GrayCoordinatesToGrayCode(nBitsPerDimension, nDimensions, vGrayCoordinates);

		ss << nBase10 << "\t";
		ss << cIO.DumpVector(nSpace0, vBase2) << "\t";
		ss << cIO.DumpVector(nSpace0, vGray) << "\t";
		ss << cIO.DumpVector(nSpace0, vGrayCoordinates) << "\t";
		ss << cIO.DumpVector(nSpace1, vBase10) << "\t";

		if (vGray == vGrayCheck)
		{
			ss << "coordinates ok\t";
		}
		else
		{
			ss << "coordinates error\t";
		}

		if (vBase2 != vStart)
		{
			if (cGC.AbsoluteValue(vPrevBase10, vBase10) == 1)
			{
				ss << "increment/decrement ok\n";
			}
			else
			{
				ss << "increment/decrement error\n";
			}
		}
		else
			ss << "\n";
		
		vPrevBase10 = vBase10;

		mSFC.insert(make_pair(nBase10, vBase10));
	
		if (vBase2 == vStop)
			break;
	}

	uint nFail = 0;
	if (cGC.CheckGrayCode(nFail, mSFC))
	{
		cout << "\nSFC Check OK\n";
		ss   << "\nSFC Check OK\n";
	}
	else
	{
		cout << "\nSFC Check Failed at position = " << nFail << "\n";
		ss   << "\nSFC Check Failed at position = " << nFail << "\n";
	}

	cout << "\nSaved in " << sFile << "\n";
	ss << "\n" << sFile << "\n\n";
	cIO.WriteFile(sFile, ss.str());
}

void XORExample()
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	string sFile = "XORExample.txt";

	uint nDimensions = 2;
	uint nBitsPerDimension = 3;
	uint nTotalBits = nDimensions * nBitsPerDimension;

	cout << "\n" << sFile << "\n";
	cout << "\nDimensions = " << nDimensions << "\n";
	cout << "\nBits Per Dimension = " << nBitsPerDimension << "\n";
	cout << "\nTotal Bits = " << nTotalBits << "\n";
	cout << "Total Length = " << pow(2, nTotalBits) << "\n";

	ss << "\n" << sFile << "\n";
	ss << "Dimensions = " << nDimensions << "\n";
	ss << "Bits Per Dimension = " << nBitsPerDimension << "\n";
	ss << "Total Bits (Dimensions * Bits Per Dimension) = " << nTotalBits << "\n";
	ss << "Total Length (2^nTotalBits) = " << pow(2, nTotalBits) << "\n";
	ss << "vBase2 is a point on the curve\n";
	ss << "Gray Coordinates are the vBase2 point converted to 2-dimensional Gray Code\n";
	ss << "x1 is the first dimensional length in gray code\n";
	ss << "x2 is the second dimensional length in gray code\n";
	ss << "XOR(x1,x2) is x1 XOR x2\n";
	ss << "XORSum is XOR(x1,x2) = y then the sum of the 1's in y\n";

	uint nSpace0 = 0;
	uint nSpace1 = 1;
	uint nSpace2 = 2;

	ss << "\n\n";
	ss << "Base10\tvBase2\tvGray\tGrayCoordinates\tx1\tx2\tXOR(x1,x2)\tXORSum \n";

	vector<bool> vStart(nTotalBits, false);
	vector<bool> vStop(nTotalBits, true);

	map<vector<bool>, vector<uint>> mSFC;
	for (vector<bool> vBase2 = vStart; vBase2 <= vStop; vBase2 = cGC.IncrementBase2(vBase2))
	{
		uint nBase10 = cGC.Base2ToBase10(vBase2);

		vector<bool> vGray = cGC.Base2ToGray(vBase2);
		vector<bool> vGrayCoordinates = cGC.GrayCodeToGrayCoordinates(nBitsPerDimension, nDimensions, vGray);

		uint nDimensionX = 0;
		vector<bool> vGrayX = cGC.ExtractFromCoordinates(nDimensionX, nBitsPerDimension, nDimensions, vGrayCoordinates);

		uint nDimensionY = 1;
		vector<bool> vGrayY = cGC.ExtractFromCoordinates(nDimensionY, nBitsPerDimension, nDimensions, vGrayCoordinates);

		vector<bool> vXORGray = cMOS.XORGray(vGrayX, vGrayY);
		uint nXORSum = cGC.GraySum(vXORGray);

		//vector<uint> vBase10(1, 0);	// kind of silly
		//vBase10[0] = nXORSum;

		ss << nBase10 << "\t\t";
		ss << cIO.DumpVector(nSpace0, vBase2) << "\t";
		ss << cIO.DumpVector(nSpace0, vGray) << "\t";
		ss << cIO.DumpVector(nSpace0, vGrayCoordinates) << "\t\t\t";
		ss << cIO.DumpVector(nSpace0, vGrayX) << "\t";
		ss << cIO.DumpVector(nSpace0, vGrayY) << "\t";
		ss << cIO.DumpVector(nSpace0, vXORGray) << "\t\t\t";
		ss << nXORSum << "\n";

		//mSFC.insert(make_pair(vBase2, vBase10));	//

		if (vBase2 == vStop)
			break;
	}

	uint nFail = 0;
	if (cGC.CheckGrayCode(nFail, mSFC))
	{
		cout << "\nSFC Check OK\n";
		ss << "\nSFC Check OK\n";
	}
	else
	{
		cout << "\nSFC Check Failed at position = " << nFail << "\n";
		ss << "\nSFC Check Failed at position = " << nFail << "\n";
	}

	cIO.WriteFile(sFile, ss.str());

	cout << "\nSaved in " << sFile << "\n";
	ss << "\n" << sFile << "\n\n";
}

void IteratePointsExample()
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	Intervals cI = Intervals();

	string sFile = "IteratePointsExample.txt";;
	cout << "\n\nIterate Points Example: Saved in: " << sFile;
	ss << "\n" << sFile << "\n";

	bool bGray = true;
	uint nSpace0 = 0;
	uint nSpace1 = 1;
	uint nSpace2 = 2;
	uint nBits = 6;
	map<vector<bool>, vector<uint> > mPoints;
	for (uint n = 0; n < nBits; n++)
	{
		if (n == 0)
		{
			mPoints = cI.IterateOrigin(nBits);
			ss << "\nIterate Origin, Bits = " << nBits << "\tGray Sum = 1" << "\n";
			ss << "\tvBase2\t\tvGray\t\tnGraySum\n";
			ss << cIO.DumpMap(bGray, nSpace0, nSpace1, mPoints);
		}
		else
		{
			map<vector<bool>, vector<uint> >::iterator i;
			map<vector<bool>, vector<uint> > mPointsTemp;
			for (i = mPoints.begin(); i != mPoints.end(); i++)
			{
				vector<bool> vBase2 = i->first;
				vector<bool> vGray = cGC.Base2ToGray(vBase2);
				uint nGraySum = cGC.GraySum(vGray);
				if (nGraySum == n)
				{
					bool bOK;
					map<vector<bool>, vector<uint> > mTemp = cI.IteratePoint(bOK, vBase2);

					ss << "\nIterate Point = " << cIO.DumpVector(nSpace0, vBase2) << "\tIterated Points From Point With Gray Sum = " << n << "\n";
					ss << "\tvBase2\t\tvGray\t\tnGraySum\n";
					ss << cIO.DumpMap(bGray, nSpace0, nSpace1, mTemp);

					mPointsTemp.insert(mTemp.begin(), mTemp.end());
				}
			}
			mPoints.insert(mPointsTemp.begin(), mPointsTemp.end());

			ss << "\nAll Iterated Points From Points With Gray Sum = " << n << "\n";
			ss << "\tvBase2\t\tvGray\t\tnGraySum\n";
			ss << cIO.DumpMap(bGray, nSpace0, nSpace1, mPointsTemp);
		}
	}

	uint nFail = 0;
	if (cGC.CheckGrayCode(nFail, mPoints))
	{
		cout << "\nSFC Check OK\n";
		ss << "\nSFC Check OK\n";
	}
	else
	{
		cout << "\nSFC Check Failed at position = " << nFail << "\n";
		ss << "\nSFC Check Failed at position = " << nFail << "\n";
	}

	ss << "\nAll Iterated Points" << "\n";
	ss << "\tvBase2\t\tvGray\t\tnGraySum\n";
	ss << cIO.DumpMap(bGray, nSpace0, nSpace1, mPoints);

	cout << "\nSaved in " << sFile << "\n";
	cIO.WriteFile(sFile, ss.str());
}

void IterateToPointExample()		//***
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	Intervals cI = Intervals();

	string sFile = "IterateToPointExample.txt";;
	cout << "\n\nIterate Points Example: Saved in: " << sFile << "\n";
	ss << "\n" << sFile << "\n";

	bool bGray = false;
	uint nSpace0 = 0;
	uint nSpace1 = 1;
	uint nSpace2 = 2;

	uint nBase2Bits = 10;

	uint nBits = 64;
	nBits = cIO.GetEntry("Bits Per Dimension = ", nBits);

	bool bOK = false;
	vector<bool> vBase2 = cGC.RandomVector(nBits);
	vector<bool> vGray = cGC.Base2ToGray(vBase2);

	cout << "\nBits = " << nBits << "\n";
	ss << "nBits = " << nBits << "\n";
	ss << "Random Point Iterated To:\n" << cIO.DumpVector(nSpace0, vBase2) << "\n";
	ss << "Gray Sum of the point = " << cGC.Base2Sum(vBase2) << "\n";

	map<vector<bool>, vector<uint>> m;
	map<vector<bool>, vector<uint>> mNext;
	m = cI.IterateToPoint(bOK, vBase2);

	ss << cIO.DumpMap(bGray, nSpace0, nSpace1, m);

	cout << "\nSaved in " << sFile << "\n";
	ss << "\n" << sFile << "\n";
	cIO.WriteFile(sFile, ss.str());
}

void PointBoundariesExample()
{
	cout << "\nVestigal\n";
}

void ConstructTrainingPointExample()
{
	cout << "\nVestigal\n";
}

void HandWrittenDigitsExample()		//***
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	HandWrittenDigits cHWD = HandWrittenDigits();
	Intervals cI = Intervals();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	string sFile = "HandWrittenDigitsExample.txt";
	cout << "\n\nHandWrittenDigits: Saved in: " << sFile << "\n";
	ss << "\n" << sFile << "\n";

	map< vector<bool>, vector<uint> >::iterator i;

	bool b32x32 = true;

	bool bClassifyOrigin = true;

	//bool bIterateToPoints = true;
	//bool bIterateSerial = true;
	//bool bIterateParallel = true;
	
	bool bIterateToPoints = true;
	bool bIterateSerial = false;
	bool bIterateParallel = false;

	bool bReOrder = false;

	if (bIterateToPoints)
	{
		bIterateSerial   = false;
		bIterateParallel = false;
	}
	else if (bIterateSerial)
	{
		bIterateToPoints = false;
		bIterateParallel = false;
	}
	else if (bIterateParallel)
	{
		bIterateToPoints = false;
		bIterateSerial = false;
	}

	bool bAllSums = true;		// vs specific sums

	bool bPrintSumsAndIndexes = true;

	bool bMinClassification = true;

	bool bDumpTrainingSet = false;
	bool bDumpTestingSet = false;

	bool bInsertRandomTestSet = false;

	bool bFocusTrainingPoint = false;

	uint nTotalClasses = 10;
	if (bFocusTrainingPoint)
	{
		nTotalClasses = 2;
	}

	uint nSpace0 = 0;
	uint nSpace1 = 1;
	uint nSpace2 = 2;
	uint nIndexPosition = 0;
	uint nClassPosition = 1;
	uint nPixelCount = 28 * 28;
	if (b32x32)
		nPixelCount = 32 * 32;
	
	uint nTrainSize = 100;
	uint nTestSize  = nTrainSize;
	
	uint nMinSumDefault = nPixelCount + 1;
	//uint nMinSumDefault = 200;
	uint nIndexDefault  = nTrainSize;
	uint nClassDefault  = nTotalClasses;
	uint nSpaceDefault = 999999;

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Train and Test with Fuzzy Base10 Pixels
	map< vector<uint>, vector<uint> > mTrainBase10;
	cHWD.GetTrainPixelsIndexClass(nTrainSize, mTrainBase10);
	cout << "\nTrain Base10 Size = " << mTrainBase10.size() << "\n";
	ss << "\nTrain Base10 Size = " << mTrainBase10.size() << "\n";
	ss << "\nTraining Base10\n" << cIO.DumpMap(nSpace1, mTrainBase10) << "\n";
	//ss << "\nTraining Set Base10 " << cIO.DumpMap(nSpace1, nSpace1, mTrainBase10) << "\n";

	map< vector<uint>, vector<uint> > mTestBase10;
	cHWD.GetTestPixelsIndexClass(nTestSize, mTestBase10);
	cHWD.AddTrainingSizeToTestIndex(nIndexPosition, nTrainSize, mTestBase10);

	cout << "\nTest Base10 Size = " << mTestBase10.size() << "\n";
	ss << "\nTest Base10 Size = " << mTestBase10.size() << "\n";
	ss << "\nTest Base10\n" << cIO.DumpMap(nSpace1, mTestBase10) << "\n";;
	//ss << "\nTest Set Base10" << cIO.DumpMap(nSpace1, nSpace1, mTestBase10) << "\n";;
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Train and Test with Fuzzy Base10 Pixels

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Euclidean Nearest Neighbor with Fuzzy Base10 Pixels
	map< vector<uint>, vector<uint> > mTestBase10Euclidean = mTestBase10;
	vector<uint> vCorrectTieErrorTotal = cMOS.EuclideanNearestNeighbor(nIndexPosition, nClassPosition, mTestBase10Euclidean, mTrainBase10);
	//ss << cIO.DumpMap(nSpace2, mTestBase10Euclidean) << "\n";

	cout << "\nTrain/Test Euclidean Nearest Neighbor with Fuzzy Base10 Pixels\n";
	cout << "Correct + Tie + Error = Total\n";
	cout << vCorrectTieErrorTotal[0] << " + " << vCorrectTieErrorTotal[1] << " + " << vCorrectTieErrorTotal[2] << " = " << vCorrectTieErrorTotal[3] << "\n\n";

	ss << "\nTrain/Test Euclidean Nearest Neighbor with Fuzzy Base10 Pixels\n";
	ss << "Correct + Tie + Error = Total\n";
	ss << vCorrectTieErrorTotal[0] << " + " << vCorrectTieErrorTotal[1] << " + " << vCorrectTieErrorTotal[2] << " = " << vCorrectTieErrorTotal[3] << "\n\n";
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Euclidean Nearest Neighbor with Fuzzy Base10 Pixels

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Change the Fuzzy Base10 Pixels to Binary Gray Pixels 32x32 - Train and Test using Gray Code - Gray is the data, Base2 is the ordering
	uint nPixelMin = 0;
	map<vector<bool>, vector<uint> > mTrain28x28Gray = cHWD.GrayInputs(nPixelMin, mTrainBase10);
	map<vector<bool>, vector<uint> > mTrain32x32Gray = cGC.Map28x28To32x32(mTrain28x28Gray);
	map<vector<bool>, vector<uint> > mTrain32x32Base2 = cGC.GrayToBase2(mTrain32x32Gray);

	map<vector<bool>, vector<uint> > mTest28x28Gray = cHWD.GrayInputs(nPixelMin, mTestBase10);
	map<vector<bool>, vector<uint> > mTest32x32Gray = cGC.Map28x28To32x32(mTest28x28Gray);
	map<vector<bool>, vector<uint> > mTest32x32Base2 = cGC.GrayToBase2(mTest32x32Gray);

	cout << "Train Base2 32x32 Size = " << mTrain32x32Base2.size() << "\n";
	cout << "Test Base2 32x32 Size = " << mTest32x32Base2.size() << "\n";

	ss << "Train Base2 32x32 Size = " << mTrain32x32Base2.size() << "\n";
	ss << "Training Base2 32x32\n";
	ss << cIO.DumpMap(nSpace1, mTrain32x32Base2) << "\n";

	ss << "Test Base2 32x32 Size = " << mTest32x32Base2.size() << "\n";
	ss << "Test Base2 32x32\n";
	ss << cIO.DumpMap(nSpace1, mTest32x32Base2);
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Change the Fuzzy Base10 Pixels to Binary Gray Pixels 32x32 - Train and Test using Gray Code - Gray is the data, Base2 is the ordering

	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Train and Test XOR - Gray Code Nearest Neighbor
	map< vector<bool>, vector<uint> > mTest32x32GrayWithAnswers = mTest32x32Gray;
	vCorrectTieErrorTotal = cMOS.XORNearestNeighbor(nIndexPosition, nClassPosition, mTest32x32GrayWithAnswers, mTrain32x32Gray);		// add correct answers to TestGrayXOR here
	
	map<vector<bool>, vector<uint> > mTest32x32Base2WithAnswers = cGC.GrayToBase2(mTest32x32GrayWithAnswers);
	ss << "\nTest Base2 With Answers\n";
	ss << cIO.DumpMap(nSpace2, mTest32x32Base2WithAnswers) << "\n";

	cout << "\nTrain/Test XOR Nearest Neighbor Gray Code\n";
	cout << "Correct + Tie + Error = Total\n";
	cout << vCorrectTieErrorTotal[0] << " + " << vCorrectTieErrorTotal[1] << " + " << vCorrectTieErrorTotal[2] << " = " << vCorrectTieErrorTotal[3] << "\n";

	ss << "\nTrain/Test XOR Nearest Neighbor Gray Code\n";
	ss << "Correct + Tie + Error = Total\n";
	ss << vCorrectTieErrorTotal[0] << " + " << vCorrectTieErrorTotal[1] << " + " << vCorrectTieErrorTotal[2] << " = " << vCorrectTieErrorTotal[3] << "\n\n";
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////	Train and Test XOR - Gray Code Nearest Neighbor

//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Random Test Set
//	map<vector<bool>, vector<uint> > mRandomTestBase2;
//	uint nRandomTestSum = 200;
//	uint nRandomTestBits = 784;
//	if (bInsertRandomTestSet)
//	{
//		for (uint n = 0; n < 100; n++)
//		{
//			vector<bool> vGray = cGC.RandomVector(nRandomTestSum, nRandomTestBits);
//			vGray = cGC.Vector28x28To32x32(vGray);
//			uint nSum = cGC.GraySum(vGray);
//
//			vector<bool> vBase2 = cGC.GrayToBase2(vGray);
//
//			uint nMinSim = 0;
//			vector<uint> vIndexes;
//			vector<uint> vClasses;
//			vector<bool> vNearestGray = cMOS.XORNearestNeighbor(nMinSim, vIndexes, vClasses, nIndexPosition, nClassPosition, vGray, mTrain32x32Gray);
//
//			vIndexes.insert(vIndexes.end(), vClasses.begin(), vClasses.end());
//			//vIndexes.push_back(nMinSim);
//			mRandomTestBase2.insert(make_pair(vBase2, vIndexes));
//		}
//	}
//
//	cout << "\nRandom Test Base2 Size = " << mRandomTestBase2.size() << "\n";
//	ss << "Random Test Base2 Size = " << mRandomTestBase2.size() << "\n";
//	if (mRandomTestBase2.size() > 0)
//	{
//		ss << cIO.DumpMap(nSpace1, mRandomTestBase2);
//	}
//	else
//	{
//		ss << "\n";
//	}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Random Test Set
// 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Single Focus Point
	uint nFocusMin = 0;
	uint nFocusIndex = 0;
	uint nFocusClass = 0;
	vector<uint> vFocusIndexClass;
	vector<bool> vFocusBase2;
	vector<bool> vFocusGray;

	map<vector<bool>, vector<uint> > mOriginalTrainingSet;
	map<vector<bool>, vector<uint> > mOriginalTrainingSubSet;
	if (bFocusTrainingPoint)
	{
		mOriginalTrainingSet = mTrain32x32Base2;

		cout << "\nSingle Focus Point\n";
		ss << "\nSingle Focus Point\n";

		nFocusClass = 0;
		map<vector<bool>, vector<uint>> mFocus = cGC.GetFocusSubSet(nFocusClass, nClassPosition, mTrain32x32Base2);
			
		vFocusBase2 = cMOS.NearestToAllXORBase2(nFocusMin, vFocusIndexClass, mFocus);
		vFocusGray = cGC.Base2ToGray(vFocusBase2);
		nFocusIndex = vFocusIndexClass[nIndexPosition];

		//uint nFocusClass = 10;
		//vector<bool> vFocusKey = cGC.FindKeyFromIndex(nIndexPosition, nClassPosition, nFocusIndex, nFocusClass, mOriginalTrainingSet);
		//vector<uint> vOriginalIndexClass(2, 0);
		//vOriginalIndexClass[0] = nFocusIndex;
		//vOriginalIndexClass[1] = nFocusClass;
		//mOriginalTrainingSubSet.insert(make_pair(vFocusKey, vOriginalIndexClass));

		//uint nFocusIndex = 81;
		//vector<bool> vFocusBase2 = cGC.FindKeyFromIndex(nIndexPosition, nClassPosition, nFocusIndex, nFocusClass, mTrain32x32Base2);
		//vector<bool> vFocusGray81 = cGC.Base2ToGray(vFocusBase2);

		//vector<uint> vFocusIndexClass(2, 0);
		//vFocusIndexClass[nIndexPosition] = nFocusIndex;
		//vFocusIndexClass[nClassPosition] = nFocusClass;
		//map< vector<bool>, vector<uint> > mFocusGray;
		//mFocusGray.insert(make_pair(vFocusGray81, vFocusIndexClass));

		ss << "\nSingle Focus Index, Class, Gray Sum: " << nFocusIndex << " " << nFocusClass << " " << cGC.GraySum(vFocusGray) << "\n";
		ss << cIO.DumpVectorMatrix(vFocusGray) << "\n";

		if (bReOrder)
		{
			cout << "\nSingle Focus Point with ReOrdering\n";
			ss << "\nSingle Focus Point with ReOrdering\n";

			map< vector<bool>, vector<uint> > mFocusGray;
			mFocusGray.insert(make_pair(vFocusGray, vFocusIndexClass));

			ss << "Focus Gray Map";
			ss << cIO.DumpMap(nSpace1, mFocusGray);

			uint nBits = 32 * 32;
			vector<uint> vFocusBitCounts = cGC.GetBitCounts(nBits, mFocusGray);
			map<uint, vector<uint>> mFocusBitCountOrder = cGC.BitCountOrder(vFocusBitCounts);
			vector<uint> vBitCountOrder = cGC.GetFinalBitCountOrder(mFocusBitCountOrder);

			mTrain32x32Gray = cGC.Base2ToGray(mTrain32x32Base2);
			mTest32x32Gray  = cGC.Base2ToGray(mTest32x32Base2);

			mTrain32x32Gray = cGC.ReOrderGray(vBitCountOrder, mTrain32x32Gray);
			mTest32x32Gray  = cGC.ReOrderGray(vBitCountOrder, mTest32x32Gray);

			mTrain32x32Base2 = cGC.GrayToBase2(mTrain32x32Gray);
			mTest32x32Base2  = cGC.GrayToBase2(mTest32x32Gray);

			vector<bool> vFocusBaseCheck1 = cGC.FindKeyFromIndex(nIndexPosition, nClassPosition, nFocusIndex, nFocusClass, mTrain32x32Base2);
			vector<bool> vFocusGrayCheck1 = cGC.Base2ToGray(vFocusBaseCheck1);

			mTrain32x32Base2 = cMOS.XORBase2(vFocusBaseCheck1, mTrain32x32Base2);
			mTest32x32Base2  = cMOS.XORBase2(vFocusBaseCheck1, mTest32x32Base2);

			mTrain32x32Gray = cGC.Base2ToGray(mTrain32x32Base2);
			mTest32x32Gray  = cGC.Base2ToGray(mTest32x32Base2);

			vector<bool> vFocusBaseCheck2 = cGC.FindKeyFromIndex(nIndexPosition, nClassPosition, nFocusIndex, nFocusClass, mTrain32x32Base2);
			vector<bool> vFocusGrayCheck2 = cGC.Base2ToGray(vFocusBaseCheck2);

			ss << "Focus Bit Counts\n";
			ss << cIO.DumpVector(nSpace1, vFocusBitCounts) << "\n";

			ss << "Bit Count Order Map\n";
			ss << cIO.DumpMap(nSpace1, mFocusBitCountOrder);

			ss << "Bit Count Order Vector\n";
			ss << cIO.DumpVector(nSpace1, vBitCountOrder) << "\n";

			ss << "Focus ReOrdered\n";
			ss << cIO.DumpVectorMatrix(vFocusGrayCheck1) << "\n";

			ss << "Focus ReOrdered XOR\n";
			ss << cIO.DumpVectorMatrix(vFocusGrayCheck2) << "\n";
		}

		mTrain32x32Base2 = cGC.BinaryIndexOutput(nFocusIndex, nIndexPosition, nClassPosition, mTrain32x32Base2);
		mTrain32x32Gray  = cGC.Base2ToGray(mTrain32x32Base2);

		vFocusBase2 = cGC.FindKeyFromIndex(nIndexPosition, nClassPosition, nFocusIndex, nFocusClass, mTrain32x32Base2);
		map<vector<bool>, vector<uint>>::iterator iFind;
		iFind = mTrain32x32Base2.find(vFocusBase2);
		vFocusIndexClass = iFind->second;

		cout << "Check Focus Index Class: " << cIO.DumpVector(nSpace1, vFocusIndexClass) << "\t" << cGC.Base2Sum(vFocusBase2) << "\n";
		ss << "Check Focus Index Class: " << cIO.DumpVector(nSpace1, vFocusIndexClass) << "\t" << cGC.Base2Sum(vFocusBase2) << "\n";

		ss << "Train Base2 32x32 Focus XOR Binary Output\n";
		ss << cIO.DumpMap(nSpace1, mTrain32x32Base2) << "\n";

		ss << "Test  Output\n";
		ss << cIO.DumpMap(nSpace1, mTest32x32Base2) << "\n";
	}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Single Focus Point

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Update Nearest Neighbor
//	map< vector<bool>, vector<uint> > mTempTrainBase2 = mTrain32x32Base2;
//	map< vector<bool>, vector<uint> > mTempTestGray = mTest32x32Gray;
//	for (i = mTempTestGray.begin(); i != mTempTestGray.end(); i++)
//	{
//		vector<bool> vTestGray = i->first;
//		vector<uint> vIndexClass = i->second;
//
//		uint nMinSim;
//		vector<uint> vIndexes;
//		vector<uint> vClasses;
//
//		vector<bool> vNearestTrainGray = cMOS.XORNearestNeighbor(nMinSim, vIndexes, vClasses, nIndexPosition, nClassPosition, vTestGray, mTrain32x32Gray);
//		vector<bool> vNearestTrainBase2 = cGC.GrayToBase2(vNearestTrainGray);
//		map< vector<bool>, vector<uint> >::iterator iFind;
//		iFind = mTempTrainBase2.find(vNearestTrainBase2);
//		if (iFind != mTempTrainBase2.end())
//		{
//			i->second.insert(i->second.end(), iFind->second.begin(), iFind->second.end());
//		}
//	}
//	map< vector<bool>, vector<uint> > mTempTestBase2 = cGC.GrayToBase2(mTempTestGray);
//	mTest32x32Base2 = mTempTestBase2;
//
//	ss << "Test  Output with Orignial Inputs\n";
//	ss << cIO.DumpMap(nSpace1, mTempTestBase2) << "\n";
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Update Nearest Neighbor

///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Variable Training Set Size

	bool bVariableTrainingSetSize = false;
	if (bVariableTrainingSetSize)
	{
		uint nVariableTrainingSetSize = 20;

		cout << "\nTraining Set Size is Altered\n";
		ss   << "\nTraining Set Size is Altered\n";
		uint nCount = 0;
		map<vector<bool>, vector<uint> >::iterator i;
		map<vector<bool>, vector<uint> > mTempSize2;

		if (bFocusTrainingPoint)
		{
			mTempSize2.insert(make_pair(vFocusBase2, vFocusIndexClass));
			nCount++;
		}

		for (i = mTrain32x32Base2.begin(); i != mTrain32x32Base2.end(); i++)
		{
			pair< map<vector<bool>, vector<uint> > ::iterator, bool > pr;
			pr = mTempSize2.insert(make_pair(i->first, i->second));
			if (pr.second)
			{
				nCount++;
			}

			if (nCount == nVariableTrainingSetSize)
			{
				break;
			}
		}
		mOriginalTrainingSet = mTrain32x32Base2;
		mTrain32x32Base2     = mTempSize2;
		mTrain32x32Gray      = cGC.Base2ToGray(mTrain32x32Base2);

		bool bBase2 = false;
		ss << "Train 32x32\n";
		ss << cIO.DumpBase2MapWithGraySums(bBase2, nSpace1, mTrain32x32Base2) << "\n";
	}
	else
	{
		cout << "\nTraining Set Size = " << mTrain32x32Base2.size() << "\n";
		ss << "\nTraining Set Size = " << mTrain32x32Base2.size() << "\n";
	}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Variable Training Set Size
// 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////// pick gray sums
	cout << "\nGrayStart, GraySize, GraySumLower, GraySumUpper\n";
	ss << "\nGrayStart, GraySize, GraySumLower, GraySumUpper\n\n";

	uint nSegments = 1;		// ***							// default
	uint nIncrement = (uint)nPixelCount / nSegments;		// default

	vector<uint> vGrayStart;
	vector<uint> vGraySize;
	vector<uint> vGraySumLower;
	vector<uint> vGraySumUpper;

	if (!bAllSums)
	{
		nSegments = 1;									// change from above here if desired
		nIncrement = (uint)nPixelCount / nSegments;

		vGrayStart.assign(nSegments, 0);
		vGraySize.assign(nSegments, nIncrement);
		vGraySumLower.assign(nSegments, 0);
		vGraySumUpper.assign(nSegments, 0);
		//vGraySumUpper.assign(nSegments, nPixelCount);

		for (uint n = 0; n < nSegments; n++)
		{
			vGrayStart[n] = n * nIncrement;
		}

		//vGrayStart[0] = 0;
		//vGraySize[0] = 934;

		vGraySumLower[0] = 0;
		vGraySumUpper[0] = 50;

		//vGrayStart[1] = 934;
		//vGraySize[1] = 90;


		//vGraySumLower[1] = 0;
		//vGraySumUpper[1] = 90;


		cout << "Select Gray Sums\n";
		cout << "Gray Start:\t";
		cout << cIO.DumpVector(nSpace1, vGrayStart) << "\n";
		cout << "Gray Size:\t";
		cout << cIO.DumpVector(nSpace1, vGraySize) << "\n";
		cout << "Gray Sum Lower:\t";
		cout << cIO.DumpVector(nSpace1, vGraySumLower) << "\n";
		cout << "Gray Sum Upper:\t";
		cout << cIO.DumpVector(nSpace1, vGraySumUpper) << "\n";

		ss << "Select Gray Sums\n";
		ss << "Gray Start:\t";
		ss << cIO.DumpVector(nSpace1, vGrayStart) << "\n";
		ss << "Gray Size:\t";
		ss << cIO.DumpVector(nSpace1, vGraySize) << "\n";
		ss << "Gray Sum Lower:\t";
		ss << cIO.DumpVector(nSpace1, vGraySumLower) << "\n";
		ss << "Gray Sum Upper:\t";
		ss << cIO.DumpVector(nSpace1, vGraySumUpper) << "\n";

		bool bBase2 = false;
		ss << "\nOriginal Train Subset\n";
		ss << cIO.DumpBase2MapWithGraySums(bBase2, nSpace1, vGrayStart, vGraySize, mOriginalTrainingSubSet) << "\n";
		ss << "Modified Train 32x32\n";
		ss << cIO.DumpBase2MapWithGraySums(bBase2, nSpace1, vGrayStart, vGraySize, mTrain32x32Base2) << "\n";


		//nSegments = 1;		// ***
		//nIncrement = (uint)nPixelCount / nSegments;
		//vGrayStart.assign(nSegments, 0);
		//vGraySize.assign(nSegments, nIncrement);
		//vGraySumLower.assign(nSegments, 0);
		//vGraySumUpper.assign(nSegments, 25);

		//nSegments = 1;		// ***
		//nIncrement = (uint)nPixelCount / nSegments;

		//vGrayStart.assign(nSegments, 0);
		//vGraySize.assign(nSegments, nIncrement);
		//vGraySumLower.assign(nSegments, 0);
		//vGraySumUpper.assign(nSegments, 0);

		//vGraySumUpper[nSegments - 1] = 201;

		//for (uint n = 0; n < nSegments; n++)
		//{
		//	vGrayStart[n] = n * nIncrement;
		//}

		//vGrayStart[0] = 0;
		//vGrayStart[1] = 823;

		//vGraySize[0] = 823;
		//vGraySize[1] = 201;

		//vGraySumLower[0] = 0;
		//vGraySumLower[1] = 0;

		//vGraySumUpper[0] = 0;
		//vGraySumUpper[1] = 201;
	}
////////////////////////////////////////////////////////////////////		// pick gray sums
////////////////////////////////////////////////////////////////////////		// pick a training point
//	if (bPickTrainingPointForGraySums)
//	{
//		bPickGraySums = false;
//
//		nSegments = 64;		// ***
//		nIncrement = (uint)nPixelCount / nSegments;
//
//		vGrayStart.assign(nSegments, 0);
//		vGraySize.assign(nSegments, nIncrement);
//		vGraySumLower.assign(nSegments, 0);
//		vGraySumUpper.assign(nSegments, 0);
//
//		for (uint n = 0; n < nSegments; n++)
//		{
//			vGrayStart[n] = n * nIncrement;
//		}
//		uint nFocusClass = 0;
//		map<vector<bool>, vector<uint>> mBase2SubSetZero = cGC.GetFocusSubSet(nFocusClass, nClassPosition, mTrain32x32Base2);
//
//		uint nArchetypeBestMin;
//		vector<uint> vArchetypeBestIndexClass;
//		vector<bool> vArchetypeBase2 = cMOS.NearestToAllXORBase2(nArchetypeBestMin, vArchetypeBestIndexClass, mBase2SubSetZero);
//		vector<bool> vArchetypeGray = cGC.Base2ToGray(vArchetypeBase2);
//
//		vector<uint> vGraySums = cGC.GraySums(vGrayStart, vGraySize, vArchetypeGray);
//		vGraySumLower = vGraySums;
//		vGraySumUpper = vGraySums;
//
//		ss << cIO.DumpVector(nSpace1, vGraySumLower) << "\n";
//		ss << cIO.DumpVector(nSpace1, vGraySumUpper) << "\n";
//
//		ss << cIO.DumpVector(nSpace1, vArchetypeBestIndexClass) << "\n";
//		ss << cIO.DumpVectorMatrix(vArchetypeGray);
//	}
///////////////////////////////////////////////////////////////////				// pick a training point
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Segment Sums
	//	29 7	102		0 0 0 0 0 0 0 0 0 0 5 10 13 11 11 7 5 5 5 5 5 6 5 4 3 2 0 0 0 0 0 0

	//cout << "Total Sum Counts = " << nTotalSumCounts << "\n";
	cout << "Segments = " << nSegments << "\n";
	cout << "Increment = " << nIncrement << "\n";
	cout << "Gray Start = " << cIO.DumpVector(nSpace1, vGrayStart) << "\n";
	cout << "Gray Size = " << cIO.DumpVector(nSpace1, vGraySize) << "\n";
	cout << "Gray Sums Lower = " << cIO.DumpVector(nSpace1, vGraySumLower) << "\n";
	cout << "Gray Sums Upper = " << cIO.DumpVector(nSpace1, vGraySumUpper) << "\n";

	//ss << cIO.DumpVector(nSpace1, vGrayIntervalCounts) << "\n";
	//ss << cIO.DumpVector(nSpace0, vGrayKey) << "\n";
	//ss << cIO.DumpVector(nSpace0, cGC.GrayToBase2(vGrayKey)) << "\n";
	//ss << "Total Sum Counts = " << nTotalSumCounts << "\n";
	ss << "SSegments = " << nSegments << "\n";
	ss << "Increment = " << nIncrement << "\n";
	ss << "Gray Start = " << cIO.DumpVector(nSpace1, vGrayStart) << "\n";
	ss << "Gray Size = " << cIO.DumpVector(nSpace1, vGraySize) << "\n";
	ss << "Gray Sums Lower = " << cIO.DumpVector(nSpace1, vGraySumLower) << "\n";
	ss << "Gray Sums Upper = " << cIO.DumpVector(nSpace1, vGraySumUpper) << "\n";

	ss << "\nTrain Gray Sums\n";
	map< vector<bool>, vector<uint> >::iterator iG;
	for (iG = mTrain32x32Gray.begin(); iG != mTrain32x32Gray.end(); iG++)
	{
		vector<bool> vGray = iG->first;
		vector<uint> vGraySums = cGC.GraySums(vGrayStart, vGraySize, vGray);
		ss << cIO.DumpVector(nSpace1, iG->second) << "\t" << cGC.GraySum(vGray) << "\t\t" << cIO.DumpVector(nSpace1, vGraySums) << "\n";
	}
	ss << "\n";
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////// Segment Sums

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Iterate Origin
	cout << "\nIterate Origin\n";
	ss << "\nIterate Origin\n";

	clock_t tStart = clock();
	//map<vector<bool>, vector<uint> > mSFC;
	map<vector<bool>, vector<uint> > mOrigin = cI.IterateOrigin(nPixelCount);
	clock_t tStop = clock();

	cout << "\nIterate Origin Size = " << mOrigin.size() << "\n";
	cout << "Time to Iterate Origin = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	cout << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	cout << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";

	ss << "\nIterate Origin Size = " << mOrigin.size() << "\n";
	ss << "Time to Iterate Origin = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	ss << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	ss << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";

	//ss << "\n" << cIO.DumpMap(nSpace1, mSFC);
	//ss << cIO.DumpMap(true, nSpace0, nSpace1, mSFC);
////////////////////////////////////////////////////////////////////////////////////////////////////////////// Iterate Origin
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// SFC Second Iteration
//	tStart = clock();
//	map<vector<bool>, vector<uint> >::iterator iTemp;
//	map<vector<bool>, vector<uint> > m = mSFC;
//	for (iTemp = m.begin(); iTemp != m.end(); iTemp++)
//	{
//		bool bOK = false;
//		map<vector<bool>, vector<uint> > mPoint = cI.IteratePoint(bOK, iTemp->first);
//		if (bOK)
//		{
//			mSFC.insert(mPoint.begin(), mPoint.end());
//		}
//	}
//	tStop = clock();
//	cout << "\nIterate SFC Size = " << mSFC.size() << "\n";
//	cout << "Time to Iterate SFC = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
//	cout << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
//	cout << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";
//
//	ss << "\nIterate SFC Size = " << mSFC.size() << "\n";
//	ss << "Time to Iterate SFC = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
//	ss << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
//	ss << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// SFC Second Iteration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Classify Origin
	cout << "Classify Origin\n";
	ss << "Classify Origin\n";

	tStart = clock();

	if(bAllSums)
	{
		cout << "\nAll Sums\n";
		ss << "\nAll Sums\n";
	}
	else
	{
		cout << "\nSpecific Sums\n";
		ss   << "\nbpecific Sums\n";
	}

	uint nReturn = 0;
	vector<bool> vFirst;
	vector<bool> vLast;

	if (bClassifyOrigin)
	{
		if (!bAllSums)
		{
			cout << "Calculate Origin Classes Specific Sums\n";
			ss << "Calculate Origin Classes Specific Sums\n";
			nReturn = cI.CalculateMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mOrigin, mTrain32x32Gray);
		}
		else if (bAllSums)
		{
			cout << "Calculate Origin Classes All Sums\n";
			ss << "Calculate Origin Classes All Sums\n";
			nReturn = cI.CalculateMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mOrigin, mTrain32x32Gray);
		}
		vector<uint> vMinSums(nTotalClasses, nPixelCount);
		vector<uint> vIndexes(nTotalClasses, nIndexDefault);
		vector<uint> vClasses(nTotalClasses, nClassDefault);
		cMOS.UpDateLastClass(vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, mOrigin, mTrain32x32Gray);
	}


	tStop = clock();
	cout << "\nClassify Origin Size = " << mOrigin.size() << "\n";
	cout << "Time to Classify Origin = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	cout << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	cout << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";

	ss << "\nClassify Origin Size = " << mOrigin.size() << "\n";
	ss << "Time to Classify Origin = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	ss << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	ss << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";

	////ss << "\n" << cIO.DumpMap(nSpace1, mOrigin);
	//ss << cIO.DumpMap(true, nSpace0, nSpace1, mOrigin);

////////////////////////////////////////////////////////////////////////////////////////////////////////////// Classify Origin

////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Classify Intervals
	tStart = clock();
	map<vector<bool>, vector<uint> > mSFC = mOrigin;

	cout << "\nClassify Intervals Initial Size = " << mSFC.size() << "\n";
	ss << "\nClassify Intervals Initial Size = " << mSFC.size() << "\n";

	//map<vector<bool>, vector<uint>>::iterator i;
	map<vector<bool>, vector<uint>>::iterator iSFC;
	map<vector<bool>, vector<uint>>::iterator iNext;
	map<vector<bool>, vector<uint>>::iterator iLower;
	map<vector<bool>, vector<uint>>::iterator iUpper;
	//map<vector<bool>, vector<uint>>::iterator iStart = mSFC.begin();
	
	if (bIterateToPoints)		//***
	{
		cout << "Iterate to Points\n";
		ss   << "Iterate to Points\n";

		if (bAllSums)
		{
			cout << "All Sums\n";
			ss << "All Sums\n";
		}
		else
		{
			cout << "Specific Sums\n";
			ss << "Specific Sums\n";
		}
		//bIterateToSums = false;

		uint nReturn = 0;

		uint nPoint = 0;
		uint nTotalPoints = 1;
		//uint nTotalPoints = (uint)mTrain32x32Base2.size();
		//for (i = mTest32x32Base2WithAnswers.begin(); i != mTest32x32Base2WithAnswers.end(); i++) 
		for (i = mTrain32x32Base2.begin(); i != mTrain32x32Base2.end(); i++)
		{
			vector<bool> vBase2 = i->first;
			vector<uint> vIndexClass = i->second;

			bool bOK = false;
			map<vector<bool>, vector<uint>> mPoints = cI.IterateToPoint(bOK, mSFC, vBase2);
			cout << "\nOK = " << bOK << "\n";
			ss << "\nOK = " << bOK << "\n";

			cout << "Point " << nPoint << " of " << nTotalPoints << "\t" << cIO.DumpVector(nSpace1, vIndexClass) << "\t" << cGC.Base2Sum(vBase2) << "\tPoints Size = " << mPoints.size() << "\tSFC Size = " << mSFC.size() << "\n";
			ss << "Point " << nPoint << " of " << nTotalPoints << "\t" << cIO.DumpVector(nSpace1, vIndexClass) << "\t" << cGC.Base2Sum(vBase2) << "\tPoints Size = " << mPoints.size() << "\tSFC Size = " << mSFC.size() << "\n";

			if (bOK && mPoints.size() > 1)
			{
				if (bAllSums)
				{
					uint nReturn = cI.CalculateMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mPoints, mTrain32x32Gray);
					mSFC.insert(mPoints.begin(), mPoints.end());
					bool bReturn = cI.UpDatePrevAndLastMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mSFC, mTrain32x32Gray);
				}
				else
				{
					nReturn = cI.CalculateMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mPoints, mTrain32x32Gray);
					mSFC.insert(mPoints.begin(), mPoints.end());
					bool bReturn = cI.UpDatePrevAndLastMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, mSFC, mTrain32x32Gray);
				}
			}
			nPoint++;
			if (nPoint == nTotalPoints)
				break;
		}
	}
	else if (bIterateSerial || bIterateParallel)	// iterate to all sums or specific sums,  not iterate to point
	{
		cout << "Iterate to Sums\n";
		ss << "Iterate to Sums\n";

		map<vector<bool>, vector<uint>>::iterator iStart = mSFC.begin();
		if (mSFC.size() > 0 && cGC.Base2Sum(iStart->first) == 0)
		{
			iStart++;
		}

		//for (uint n = 0; n < 1000; n++)
		//{
		//	iStart++;
		//}

		if (bIterateSerial)
		{
			cout << "Iterate Serial\n";
			ss << "Iterate Serial\n";

			uint nMaxLoops = 0;
			//uint nMaxLoops = 1;
			for (uint nLoop = 0; nLoop < nMaxLoops; nLoop++)
			{
				cout << "Seril Loop " << nLoop << " of " << nMaxLoops << "\tSFC Size = " << mSFC.size() << "\n";
				ss << "Serial Loop " << nLoop << " of " << nMaxLoops << "\tSFC Size = " << mSFC.size() << "\n";

				vector<bool> vFirst;
				vector<bool> vLast;

				vector<bool> vStart;
				vector<bool> vStop;

				for (i = iStart; i != mSFC.end(); i++)
				{
					vStart = i->first;
					vector<uint> vStartIndexClass = i->second;
					vector<uint> vClasses = i->second;
					uint nClassCount = cGC.ClassCount(bPrintSumsAndIndexes, nClassDefault, nTotalClasses, vClasses);

					if (nClassCount > 1)
					{
						iNext = i;
						iNext++;
						if (iNext == mSFC.end())
						{
							nLoop = nMaxLoops;
							break;
						}
						vStop = iNext->first;

						if (cGC.IncrementBase2(vStart) == vStop)
						{
							cout << "vStart + 1 == vStop\n";
							ss << "vStart + 1 == vStop\n";

							bool bIncrementOK = false;
							vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
							vector<uint> vIndexes(nTotalClasses, nIndexDefault);
							vector<uint> vClasses(nTotalClasses, nClassDefault);
							i->second = cMOS.XORBase2PointClassification(bIncrementOK, bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vMinSums, vIndexes, vClasses, vStart, mTrain32x32Gray);
							iStart = mSFC.upper_bound(vStart);
							//iStart->second.clear();
							//i->second.push_back(88888);
							break;
						}

						bool bOKTemp = false;
						vector<bool> vSumFirst;
						vector<bool> vSumLast;
						map<vector<bool>, vector<uint>> mInterval = cI.IteratePoint(bOKTemp, vStart);
						cout << "Iterate Point Size = " << mInterval.size() << "\n";
						ss << "Iterate Point Size = " << mInterval.size() << "\n";

						bool bClassCount = true;
						bool bGray = false;
						uint nDefault = 999999;

						if (bAllSums)
						{
							cout << "All Sums\n";
							ss << "All Sums\n";

							if (bOKTemp && mInterval.size() > 0)
							{
								nReturn = cI.CalculateMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mInterval, mTrain32x32Gray);
								mSFC.insert(mInterval.begin(), mInterval.end());
								bool bReturn = cI.UpDatePrevAndLastMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mSFC, mTrain32x32Gray);
							}
						}
						else
						{
							cout << "Specific Sums\n";
							ss << "Specific Sums\n";

							if (bOKTemp && mInterval.size() > 0)
							{
								nReturn = cI.CalculateMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mInterval, mTrain32x32Gray);
								mSFC.insert(mInterval.begin(), mInterval.end());
								bool bReturn = cI.UpDatePrevAndLastMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mSFC, mTrain32x32Gray);

							}
						}
						iStart = mSFC.upper_bound(vStart);
						//iStart->second.clear();
						//i->second.push_back(1000 + nLoop);
						break;
					}
				}
			}
		}
		else if (bIterateParallel)
		{
			cout << "Iterate Parallel\n";
			ss << "Iterate Parallel\n";

			 //uint nMaxLoops = 0;
			uint nMaxLoops = 3;
			for (uint nLoop = 0; nLoop < nMaxLoops; nLoop++)
			{
				cout << "Parallel Loop " << nLoop << " of " << nMaxLoops << "\tSFC Size = " << mSFC.size() << "\n";
				ss << "Parrallel Loop " << nLoop << " of " << nMaxLoops << "\tSFC Size = " << mSFC.size() << "\n";

				vector<bool> vFirst;
				vector<bool> vLast;

				vector<bool> vStart;
				vector<bool> vStop;

				for (i = iStart; i != mSFC.end(); i++)
				{
					vStart = i->first;
					vector<uint> vStartIndexClass = i->second;
					vector<uint> vClasses = i->second;
					uint nClassCount = cGC.ClassCount(bPrintSumsAndIndexes, nClassDefault, nTotalClasses, vClasses);

					if (nClassCount > 1)
					{
						iNext = i;
						iNext++;
						if (iNext == mSFC.end())
						{
							nLoop = nMaxLoops;
							break;
						}
						vStop = iNext->first;

						if (cGC.IncrementBase2(vStart) == vStop)
						{
							cout << "vStart + 1 == vStop\n";
							ss << "vStart + 1 == vStop\n";

							bool bIncrementOK = false;
							vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
							vector<uint> vIndexes(nTotalClasses, nIndexDefault);
							vector<uint> vClasses(nTotalClasses, nClassDefault);
							i->second = cMOS.XORBase2PointClassification(bIncrementOK, bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vMinSums, vIndexes, vClasses, vStart, mTrain32x32Gray);
							iStart = mSFC.upper_bound(vStart);
							break;
						}

						bool bOKTemp = false;
						vector<bool> vSumFirst;
						vector<bool> vSumLast;
						map<vector<bool>, vector<uint>> mInterval = cI.IteratePoint(bOKTemp, vStart);
						cout << "Iterate Point Size = " << mInterval.size() << "\n";
						ss << "Iterate Point Size = " << mInterval.size() << "\n";

						bool bClassCount = true;
						bool bGray = false;
						uint nDefault = 999999;

						if (bIterateSerial)
						{
							cout << "Serial\t";
							ss << "Serial\t";
						}
						if (bIterateParallel)
						{
							cout << "Parallel\t";
							ss << "Parallel\t";
						}
						if (bAllSums)
						{
							cout << "All Sums\n";
							ss << "All Sums\n";

							if (bOKTemp && mInterval.size() > 0)
							{
								nReturn = cI.CalculateMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mInterval, mTrain32x32Gray);
								mSFC.insert(mInterval.begin(), mInterval.end());
								bool bReturn = cI.UpDatePrevAndLastMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mSFC, mTrain32x32Gray);
							}
						}
						else
						{
							cout << "Specific Sums\n";
							ss << "Specific Sums\n";

							if (bOKTemp && mInterval.size() > 0)
							{
								nReturn = cI.CalculateMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mInterval, mTrain32x32Gray);
								mSFC.insert(mInterval.begin(), mInterval.end());

								bool bReturn = cI.UpDatePrevAndLastMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vSumFirst, vSumLast, mSFC, mTrain32x32Gray);
							}
						}
						//else if (bIterateParallel)
						{
							bool bOK2 = false;
							vector<bool> vTempUpperBound = cGC.IncrementBase2SameGraySum(bOK2, vStart);
							iStart = mSFC.lower_bound(vTempUpperBound);
							break;
						}
					}
				}
			}
		}
	}

	bool bGraySums = true;
	bool bClassCount = true;
	uint nDefault = 999999;

	////ss << cIO.DumpMapWithDefaultSpacing(nDefault, nSpace2, mSFC);
	ss << cIO.DumpMapWithDefaultSpacing(bClassCount, nClassDefault, nDefault, nSpace2, mSFC);
	//ss << cIO.DumpMapWithDefaultSpacingII(bClassCount, nTotalClasses, nClassDefault, nDefault, nSpace2, mSFC);
	////ss << cIO.DumpMapWithDefaultSpacing(bGraySums, vGrayStart, vGraySize, bClassCount, nDefault, nSpace2, mSFC);
	////ss << cIO.DumpMap(nSpace1, mSFC);
	//ss << cIO.DumpMap(false, nDefault, nSpace0, nSpace2, mSFC);

	tStop = clock();

	cout << "\nTime to Classify Intervals = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	cout << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	cout << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";

	ss << "\nTime to Classify Intervals = " << (float)(tStop - tStart) / CLOCKS_PER_SEC << " seconds\n";
	ss << "Minutes = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / 60 << "\n";
	ss << "Hours   = " << ((float)(tStop - tStart) / CLOCKS_PER_SEC) / (60 * 60) << "\n\n";
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Classify Intervals

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Insert Test and Train Set
	map<vector<bool>, vector<uint> > ::iterator iTrain;
	map<vector<bool>, vector<uint> > ::iterator iTest;

	//bDumpTrainingSet = true;
	if (bDumpTrainingSet)
	{
		for (iTrain = mTrain32x32Base2.begin(); iTrain != mTrain32x32Base2.end(); iTrain++)
		{
			map<vector<bool>, vector<uint> > ::iterator iSFC;
			pair< map<vector<bool>, vector<uint> > ::iterator, bool > pr;
			pr = mSFC.insert(make_pair(iTrain->first, iTrain->second));
			if (!pr.second)
			{
				pr.first->second.insert(pr.first->second.end(), iTrain->second.begin(), iTrain->second.end());
			}
		}
	}
	if (bDumpTestingSet)
	{
		for (iTest = mTest32x32Base2.begin(); iTest != mTest32x32Base2.end(); iTest++)
		{
			pair< map<vector<bool>, vector<uint> > ::iterator, bool > pr;
			pr = mSFC.insert(make_pair(iTest->first, iTest->second));
			if (!pr.second)
			{
				iTest->second.insert(iTest->second.end(), pr.first->second.begin(), pr.first->second.end());
			}
		}
	}
	//if (bInsertRandomTestSet)
	//{
	//	for (iTest = mRandomTestBase2.begin(); iTest != mRandomTestBase2.end(); iTest++)
	//	{
	//		pair< map<vector<bool>, vector<uint> > ::iterator, bool > pr;
	//		pr = mSFC.insert(make_pair(iTest->first, iTest->second));
	//		if (!pr.second)
	//		{
	//			iTest->second.insert(iTest->second.end(), pr.first->second.begin(), pr.first->second.end());
	//		}
	//	}
	//}
	if (bDumpTrainingSet || bDumpTestingSet || bInsertRandomTestSet)
	{
		////ss << cIO.DumpMap(nSpace1, mSFC);
		//////ss << cIO.DumpMap(false, nSpace0, nSpace1, mSFC);
		//ss << cIO.DumpMapWithDefaultSpacing(bClassCount, nClassDefault, nDefault, nSpace2, mSFC);
		ss << cIO.DumpMapWithDefaultSpacingII(bClassCount, nTotalClasses,  nClassDefault, nDefault, nSpace2, mSFC);
	}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Insert Test and Train Set
	cout << "\nSaved in " << sFile << "\n";
	ss << "\n" << sFile << "\n";
	cIO.WriteFile(sFile, ss.str());
}

void Test()
{
	ostringstream ss;
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	string sFile = "TestII.txt";
	ss << "\n\n";

	uint nSum = 20;
	uint nBits = 100;
	uint nSpace0 = 0;
	for (uint n = 0; n < 10; n++)
	{
		vector<bool> v = cGC.RandomVector(nSum, nBits);
		uint nSum = cGC.GraySum(v);
		ss << n << "\t" << nSum << "\t" << cIO.DumpVector(nSpace0, v) << "\n";
	}

	cout << "\nSaved in " << sFile << "\n";
	ss << "\n" << sFile << "\n\n";
	cIO.WriteFile(sFile, ss.str());
}

