// Intervals.cpp

#include <algorithm> 

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

Intervals::Intervals() {}
Intervals::~Intervals() {}

vector<bool> Intervals::EqualLeft(vector<bool> v1, vector<bool> v2)
{
	vector<bool> vEqualLeft;
	
	if (v1.size() == v2.size())
	{
		for (uint n = 0; n < v1.size(); n++)
		{
			if (v1[n] == v2[n])
			{
				vEqualLeft.push_back(v1[n]);
			}
			else
			{
				return vEqualLeft;
			}
		}
	}
	return vEqualLeft;
}

vector<bool> Intervals::Base2EqualLeftGray(vector<bool> vLowerBound, vector<bool> vUpperBound)
{
	GrayCode cGC = GrayCode();
	vector<bool> vLowerGray = cGC.Base2ToGray(vLowerBound);
	vector<bool> vUpperGray = cGC.Base2ToGray(vUpperBound);
	return EqualLeft(vLowerGray, vUpperGray);
}

vector<bool> Intervals::InsertLeft(vector<bool> vLeft, vector<bool> v)
{
	if (vLeft.size() <= v.size())
	{
		for (uint n = 0; n < vLeft.size(); n++)
			v[n] = vLeft[n];
	}
	return v;
}

vector<bool> Intervals::InsertLeftGrayReturnBool(vector<bool> vLeftGray, vector<bool> vBase2)
{
	GrayCode cGC = GrayCode();
	
	vector<bool> vGray = cGC.Base2ToGray(vBase2);
	
	if (vLeftGray.size() <= vGray.size())
	{
		for (uint n = 0; n < vLeftGray.size(); n++)
			vGray[n] = vLeftGray[n];
	}
	return cGC.GrayToBase2(vGray);
}

vector<bool> Intervals::BoundedGraySum(bool& bOK, uint nSumLower, uint nSumUpper, vector<bool> vGray)
{
	GrayCode cGC = GrayCode();

	bOK = false;
	vector<bool> vError(vGray.size(), false);

	if (vGray.size() == 0)
		return vError;

	if (nSumLower <= cGC.GraySum(vGray) && cGC.GraySum(vGray) <= nSumUpper)
	{
		bOK = true;
		return vGray;
	}

	//cout << nSumLower << " " << nSumUpper << "\t";

	if (nSumLower <= vGray.size() && nSumLower <= nSumUpper)
	{
		for (int n = (int)vGray.size() - 1; n >= 0; n--)
		{
			if (cGC.GraySum(vGray) < nSumLower && !vGray[n])
			{
				vGray[n] = true;
			}
			else if (cGC.GraySum(vGray) > nSumUpper && vGray[n])
			{
				vGray[n] = false;
			}
			if (nSumLower <= cGC.GraySum(vGray) && cGC.GraySum(vGray) <= nSumUpper)
			{
				bOK = true;
				//cout << cGC.GraySum(vGray) << " ";
				return vGray;
			}
		}
	}
	bOK = false;
	return vError;
}

vector<bool> Intervals::BoundedBase2(bool& bOK, vector<bool> vLowerBound, vector<bool> vUpperBound, vector<bool> vBase2)
{																			//  for the two bit xy format here 'x' is the nth lower bound bit and 'y' nth is the upper bound bit
	bOK = false;
	vector<bool> vError(vBase2.size(), false);
	if (vBase2.size() == vLowerBound.size() && vLowerBound.size() == vUpperBound.size())
	{
		uint nType = 0;
		for (uint n = 0; n < vLowerBound.size(); n++)
		{
			if (vLowerBound[n] == vUpperBound[n] && nType < 3)				// 00 or 11
			{
				if (!vLowerBound[n])
					nType = 1;												// 00
				else
					nType = 2;												// 11

				vBase2[n] = vLowerBound[n];
			}
			else if (!vLowerBound[n] && vUpperBound[n] && nType == 1)		// 01 and previous 00
			{
				nType = 3;
				vBase2[n] = true;
			}
			else if (vUpperBound[n] && nType == 3)							// x1 and previous (01 and previous 00)	- Then Return
			{
				bOK = true;
				vBase2[n] = false;
				return vBase2;
			}
			else if (!vLowerBound[n] && vUpperBound[n] && nType == 2)		// 01 and previous 11
			{
				nType = 4;
				vBase2[n] = false;
			}
			else if (!vLowerBound[n] && nType == 4)							// 0y and previous (01 and previous 11)	- Then Return
			{
				bOK = true;
				vBase2[n] = true;
				return vBase2;
			}
			else if (!vLowerBound[n] && vUpperBound[n] && nType == 0)		// 01 at beginning - (Most Significant Bits)		Note: 10 cannot occur at the beginning because the lower and upper bounds are ordered
			{
				nType = 3;
				vBase2[n] = true;
			}
		}
		return vError;
	}
	return vError;
}

vector<bool> Intervals::BoundedBase2AndGray(bool& bOK, vector<bool> vBase2Lower, vector<bool> vBase2Upper, vector<uint> vGrayStart, vector<uint> vGraySize, vector<uint> vSumLower, vector<uint> vSumUpper, vector<bool> vBase2)
{
	GrayCode cGC = GrayCode();

	bOK = false;
	vector<bool> vError(vBase2.size(), false);
	uint nTotalGraySum = cGC.SumVector(vGraySize);

	if (nTotalGraySum != vBase2.size() || vSumLower.size() != vSumUpper.size())
	{
		cout << "\nTotalGraySize != vBase2.size()***Intervals::GraySumBounded***\n";		// arrange for overlapping intervals - later
		bOK = false;		// already false
		return vError;
	}

	vector<bool> vGray = cGC.Base2ToGray(vBase2);
	vector<bool> vTempGray = cGC.Base2ToGray(vBase2);
	vector<bool> vTempBase2 = vBase2;

	for (uint n = 0; n < vSumLower.size(); n++)
	{
		uint nPos = vGrayStart[n];
		uint nSize = vGraySize[n];

		if (nPos + nSize > (uint)vBase2.size())
		{
			cout << "\nnPos + nSize > (uint)vBase2.size()***Intervals::GraySumBounded***\n";
			bOK = false;		// already false
			return vError;
		}

		vector<bool> vGraySegment;
		vGraySegment.assign(vGray.begin() + nPos, vGray.begin() + nPos + nSize);

		if (vSumLower[n] <= cGC.GraySum(vGraySegment) && cGC.GraySum(vGraySegment) <= vSumUpper[n])
		{
			// nop because ok
		}
		else
		{
			for (int a = nSize - 1; a >= 0; a--)
			{
				//cout << n << " " << a << " | ";

				vector<bool> vLocalGray = vTempGray;
				if (cGC.GraySum(vGraySegment) < vSumLower[n] && !vGraySegment[a])
				{
					vGraySegment[a] = true;
					vTempGray[nPos + a] = true;

					if (cGC.GrayToBase2(vTempGray) < vBase2Lower || vBase2Upper < cGC.GrayToBase2(vTempGray) || cGC.GrayToBase2(vTempGray) < cGC.GrayToBase2(vLocalGray))		// getting worse, undo
					{
						vGraySegment[a] = false;
						vTempGray[nPos + a] = false;
					}
				}
				else if (cGC.GraySum(vGraySegment) > vSumLower[n] && vGraySegment[a])
				{
					vGraySegment[a] = false;
					vTempGray[nPos + a] = false;

					if (cGC.GrayToBase2(vTempGray) < vBase2Lower || vBase2Upper < cGC.GrayToBase2(vTempGray) || cGC.GrayToBase2(vTempGray) > cGC.GrayToBase2(vLocalGray))		// getting worse, undo
					{
						vGraySegment[a] = true;
						vTempGray[nPos + a] = true;
					}
				}

				if (vSumLower[n] <= cGC.GraySum(vGraySegment) && cGC.GraySum(vGraySegment) <= vSumUpper[n])
				{
					break;
				}
			}

			if (vSumLower[n] > cGC.GraySum(vGraySegment) || cGC.GraySum(vGraySegment) > vSumUpper[n])
			{
				bOK = false;
				return vError;
			}
		}

	}
	vTempBase2 = cGC.GrayToBase2(vTempGray);

	if (vBase2Lower <= vTempBase2 && vTempBase2 < vBase2Upper)
	{
		bOK = true;
		return vTempBase2;
	}

	bOK = false;
	return vError;
}

vector<bool> Intervals::BoundedBase2AndGrayII(bool& bOK, vector<bool> vBase2Lower, vector<bool> vBase2Upper, vector<uint> vGrayStart, vector<uint> vGraySize, vector<uint> vSumLower, vector<uint> vSumUpper, vector<bool> vBase2)
{
	GrayCode cGC = GrayCode();

	bOK = false;
	vector<bool> vError(vBase2.size(), false);
	vector<bool> vGray = cGC.Base2ToGray(vBase2);

	for (uint n = 0; n < vSumLower.size(); n++)
	{
		uint nPos = vGrayStart[n];
		uint nSize = vGraySize[n];

		if (nPos + nSize > (uint)vBase2.size())
		{
			cout << "\nnPos + nSize > (uint)vBase2.size()***Intervals::GraySumBounded***\n";
			bOK = false;		// already false
			return vError;
		}

		vector<bool> vGraySegment;
		vGraySegment.assign(vGray.begin() + nPos, vGray.begin() + nPos + nSize);


	}

	return vector<bool>();
}

vector<bool> Intervals::Base2GreaterThanOrEqualToLowerLessThanUpper(bool& bOK, vector<bool> vLowerBound, vector<bool> vUpperBound, vector<bool> vBase2)
{//  for the two bit xy format here 'x' is the nth lower bound bit and 'y' nth is the upper bound bit
	bOK = false;
	vector<bool> vError(vBase2.size(), false);
	if (vBase2.size() == vLowerBound.size() && vLowerBound.size() == vUpperBound.size())
	{
		uint nType = 0;
		for (uint n = 0; n < vLowerBound.size(); n++)
		{
			if (vLowerBound[n] == vUpperBound[n] && nType == 0)				// 00 or 11
			{
				vBase2[n] = vLowerBound[n];
			}
			else if (!vLowerBound[n] && vUpperBound[n] && nType == 0)		// previous 00 or 11 and now 01	so make vBase2 less than upper bound
			{
				nType = 1;													//	vBase2 less than upper bound
				vBase2[n] = false;
			}
			else if (vLowerBound[n] && !vUpperBound[n] && nType == 0)		// previous 00 or 11 and now 10	which is not possible since lower would be greater than upper
			{
				cout << "\n***Error: Intervals::Base2GreaterThanOrEqualToLowerLessThanUpper - this should not occur***\n";
				return vError;
			}
			else if (!vLowerBound[n] && vBase2[n] && nType == 1)		// nType == 1 means less than upper bound and here vBase2 is greater than lower bound
			{
				bOK = true;
				return vBase2;
			}
			else if (vLowerBound[n] && !vBase2[n] && nType == 1)		// nType == 1 means less than upper bound and here vBase2 was is less than lower bound
			{
				vBase2[n] = true;
			}
			else if (vLowerBound[n] == vBase2[n] && nType == 1)		// nType == 1 means less than upper bound and here so far lower bound == vBase2
			{
				// nop
			}
		}
		bOK = true;
		return vBase2;
	}
	return vError;
}

bool Intervals::AbleToIterate(vector<bool> vBase2)
{
	GrayCode cGC = GrayCode();

	if (cGC.Base2Sum(vBase2) == 0)							// all 0's
		return false;

	if (cGC.GraySum(vBase2) == vBase2.size())				// all 1's
		return false;

	vector<bool> vIncrement = cGC.IncrementBase2(vBase2);
	if (cGC.Base2Sum(vIncrement) < cGC.Base2Sum(vBase2))	// Every iteration must increase the Gray Sum (the number of 1's), if not, there will be duplicates.
		return false;

	return true;
}

map<vector<bool>, vector<uint> > Intervals::IteratePoint(bool& bOK, vector<bool> v)
{
	bOK = false;
	GrayCode cGC = GrayCode();

	vector<uint> vIndexClassSum(3, 0);			// for no particular reason - need a place holder - holds index,class,sum
	map<vector<bool>, vector<uint> > mNext;

	bool bOK1 = false;
	vector<bool> vIncrement = cGC.IncrementBase2IncrementGraySum(bOK1, v);		// incrementing Base2 and incrementing the Gray sum gives a smaller number than incrementing Base2 with same Gray sum

	if (bOK1)
	{
		bool bOK2 = false;
		vector<bool> vUpperBound = cGC.IncrementBase2SameGraySum(bOK2, v);		// ??? vIncrement(Base2) < vUpperBound(Base2) and vIncrement(GraySum) > vUpperBound(GraySum) ???

		if (bOK2)
		{
			while (vIncrement < vUpperBound)									// note: max loops is v.size() for IncrementBoolSameSim(v);	
			{
				vIndexClassSum[2] = cGC.Base2Sum(vIncrement);				// this is not necessary - it is for debugging

				mNext.insert(make_pair(vIncrement, vIndexClassSum));

				if (cGC.IncrementBase2(vIncrement) == vUpperBound)				// at the end of the line so stop ie vIncrement next to the upper bound
				{
					bOK = true;
					return mNext;
				}

				bool bOK3 = false;
				vIncrement = cGC.IncrementBase2SameGraySum(bOK3, vIncrement);	// not always possible to increment bool and increment sim so the previous line is necessary
				if (!bOK3)
				{
					return mNext;
				}
			}
		}
	}
	return mNext;
}

map<vector<bool>, vector<uint>> Intervals::IterateOrigin(uint nBits)
{
	GrayCode cGC = GrayCode();

	uint nReturn     = 0;
	uint nCountsSize = 6;
	vector<uint> vBase2Counts;
	vector<uint> vGrayCounts;
	
	bool bOK = false;
	vector<bool> v(nBits, false);
	vector<uint> vIndexClassSim(3, 0);				// size == three index, class, gray sum
	
	map<vector<bool>, vector<uint> > m;
	m.insert(make_pair(v, vIndexClassSim));			// zero
	vIndexClassSim[2] = 1;							// number of gray bits

	for (uint n = 0; n < nBits; n++)
	{
		vector<bool> vGray(nBits, false);
		vGray[n] = true;
		vector<bool> vBase2 = cGC.GrayToBase2(vGray);
		m.insert(make_pair(vBase2, vIndexClassSim));
	}
		return m;
}

map<vector<bool>, vector<uint>> Intervals::IterateOrigin(uint nIterations, uint nBits)		//???
{
	map<vector<bool>, vector<uint> > m = IterateOrigin(nBits);
	for (uint n = 1; n < nIterations; n++)
	{
		map<vector<bool>, vector<uint> >::iterator i;
		map<vector<bool>, vector<uint> > mTemp = m;
		m.clear();
		for (i = mTemp.begin(); i != mTemp.end(); i++)
		{
			vector<bool> vBase2 = i->first;

			bool bOK = false;
			map<vector<bool>, vector<uint>> mPoint = IteratePoint(bOK, vBase2);
			m.insert(mPoint.begin(), mPoint.end());
		}
	}
	return m;
}

map<vector<bool>, vector<uint>> Intervals::IterateToPoint(bool& bOK, vector<bool> vBase2)
{	
	map<vector<bool>, vector<uint>> mFirstIteration = IterateOrigin((uint)vBase2.size());
	return IterateToPoint(bOK, mFirstIteration, vBase2);
}

map<vector<bool>, vector<uint>> Intervals::IterateToPointBounded(bool& bOK, vector<bool> vLowerBound, vector<bool> vUpperBound, vector<bool> vBase2)
{
	map<vector<bool>, vector<uint>> mBounded;
	map<vector<bool>, vector<uint>> mPoint = IterateToPoint(bOK, vBase2);
	if (bOK && mPoint.size() > 0)
	{
		map<vector<bool>, vector<uint>>::iterator i;
		for (i = mPoint.begin(); i != mPoint.end(); i++)
		{
			if (vLowerBound < i->first && i->first < vUpperBound)
			{
				mBounded.insert(make_pair(i->first, i->second));
			}
		}
	}
	return mBounded;
}

map<vector<bool>, vector<uint>> Intervals::IterateToPoint(bool& bOK, map<vector<bool>, vector<uint>> mFirstIteration, vector<bool> vBase2)
{
	bOK = false;
	GrayCode cGC = GrayCode();
	vector<bool> vGray = cGC.Base2ToGray(vBase2);

	if (cGC.GraySum(vGray) == 0)
		return mFirstIteration;

	map<vector<bool>, vector<uint>> mSFC;
	map<vector<bool>, vector<uint>> mPoint = mFirstIteration;

	map<vector<bool>, vector<uint>>::iterator iLowerBound;
	for (uint n = 1; n <= vBase2.size(); n++)
	{
		iLowerBound = mPoint.lower_bound(vBase2);
		if (iLowerBound != mPoint.end())
		{
			if (iLowerBound->first == vBase2)
			{
				bOK = true;
				iLowerBound->second[0] = cGC.GraySum(vGray);	// sum of 1's in vector as GrayCode == iterations == n == iLowerBound->second[2]
				iLowerBound->second[1] = n;									// iterations to the point == iLowerBound->second[2] 
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				return mSFC;
			}
			if (iLowerBound != mPoint.begin())
			{
				bool bOK2 = false;
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				iLowerBound--;
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				mPoint = IteratePoint(bOK2, iLowerBound->first);
				if (!bOK2)
				{
					cout << "\n***Error #0 - Intervals::IterateToPoint IteratePoint failed - this should not occur***\n";
					break;
				}
			}
			else
			{
				cout << "\n***Error #1 - Intervals::IterateToPoint iLowerBound == mPoint.begin() && iLowerBound->first != vBase2 - this should not occur***\n";
				break;
			}
		}
		else
		{
			cout << "\n***Error #2 - Intervals::IterateToPoint end of map - this should not occur***\n";
			break;
		}
	}
	return mSFC;
}

map<vector<bool>, vector<uint>> Intervals::IterateToPointNotAsEfficient(bool& bOK, map<vector<bool>, vector<uint>> mFirstIteration, vector<bool> vBase2)
{
	bOK = false;
	GrayCode cGC = GrayCode();
	vector<bool> vGray = cGC.Base2ToGray(vBase2);

	if (cGC.GraySum(vGray) == 0)
		return mFirstIteration;

	map<vector<bool>, vector<uint>> mSFC;
	map<vector<bool>, vector<uint>> mPoint = mFirstIteration;

	map<vector<bool>, vector<uint>>::iterator iLowerBound;
	for (uint n = 0; n <= vBase2.size(); n++)
	{
		iLowerBound = mPoint.lower_bound(vBase2);
		if (iLowerBound != mPoint.end())
		{
			if (iLowerBound->first == vBase2)
			{
				bOK = true;
				iLowerBound->second[0] = cGC.GraySum(vGray);						// sum of 1's in vector as GrayCode == iterations == n == iLowerBound->second[2]
				iLowerBound->second[1] = n;											// iterations to the point == iLowerBound->second[2] 
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				return mSFC;
			}
			if (iLowerBound != mPoint.begin())
			{
				bool bOK2 = false;
				iLowerBound--;
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				mPoint = IteratePoint(bOK2, iLowerBound->first);
				if (!bOK2)
				{
					cout << "\n***Error #0 - Intervals::IterateToPoint IteratePoint failed - this should not occur***\n";
					break;
				}
			}
			else
			{
				cout << "\n***Error #1 - Intervals::IterateToPoint iLowerBound == mPoint.begin() && iLowerBound->first != vBase2 - this should not occur***\n";
				break;
			}

		}
		else
		{
			cout << "\n***Error #2 - Intervals::IterateToPoint end of map - this should not occur***\n";
			break;
		}

	}








	for (uint n = 1; n <= vBase2.size(); n++)
	{
		iLowerBound = mPoint.lower_bound(vBase2);
		if (iLowerBound != mPoint.end())
		{
			if (iLowerBound->first == vBase2)
			{
				bOK = true;
				iLowerBound->second[0] = cGC.GraySum(vGray);						// sum of 1's in vector as GrayCode == iterations == n == iLowerBound->second[2]
				iLowerBound->second[1] = n;											// iterations to the point == iLowerBound->second[2] 
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				return mSFC;
			}
			else if (iLowerBound != mPoint.begin())
			{
				bool bOK2 = false;
				iLowerBound--;
				mSFC.insert(make_pair(iLowerBound->first, iLowerBound->second));
				mPoint = IteratePoint(bOK2, iLowerBound->first);
				if (!bOK2)
				{
					cout << "\n***Error #0 - Intervals::IterateToPoint IteratePoint failed - this should not occur***\n";
					break;
				}
			}
			else
			{
				cout << "\n***Error #1 - Intervals::IterateToPoint iLowerBound == mPoint.begin() && iLowerBound->first != vBase2 - this should not occur***\n";
				break;
			}
		}
		else
		{
			cout << "\n***Error #2 - Intervals::IterateToPoint end of map - this should not occur***\n";
			break;
		}
	}
	return mSFC;
}

map<vector<bool>, vector<uint>> Intervals::IterateToSum(bool& bOK, uint nSum, vector<bool> vBase2)
{
	GrayCode cGC = GrayCode();

	bOK = false;
	uint nMaxSum = cGC.Base2Sum(vBase2);
	map<vector<bool>, vector<uint>>::iterator iLowerBound;
	map<vector<bool>, vector<uint>> mNext = IterateOrigin((uint)vBase2.size());

	if (nSum <= nMaxSum)
	{
		for (uint n = 1; n <= vBase2.size(); n++)	// n = 0 is origin first entry all zeros which cannot be iterated
		{
			iLowerBound = mNext.lower_bound(vBase2);
			if (iLowerBound != mNext.end())
			{
				if (cGC.Base2Sum(iLowerBound->first) == nSum)
				{
					bOK = true;
					return mNext;
				}

				if (iLowerBound != mNext.begin())
				{
					iLowerBound--;
					mNext = IteratePoint(bOK, iLowerBound->first);
					if (!bOK)
						return mNext;
				}
			}
		}
	}
	bOK = false;		// already false
	return mNext;
}
//	***
uint Intervals::CalculateIntervalClassesAllSums(bool bMinClassification, uint nClassDefault, vector<uint>& vMinSums, vector<uint>& vIndexes, vector<uint>& vClasses, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vLowerBoundBase2, vector<bool> vUpperBoundBase2, map<vector<bool>, vector<uint>> mTrainGray)
{
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	vector<uint> vTempIndexes;
	vector<uint> vTempClasses;

	bool bReturn = false;
	uint nMinSum = (uint)vLowerBoundBase2.size();

	vector<bool> vGrayLower = cGC.Base2ToGray(vLowerBoundBase2);
	vector<bool> vGrayUpper = cGC.Base2ToGray(vUpperBoundBase2);;

	nMinSum = cMOS.XORPointClassification(nIndexPosition, nClassPosition, vTempIndexes, vTempClasses, vGrayLower, mTrainGray);
	bReturn = cMOS.UpDateVectors(nTotalClasses, nMinSum, vTempIndexes, vTempClasses, vMinSums, vIndexes, vClasses);

	if (cGC.IncrementBase2(vLowerBoundBase2) == vUpperBoundBase2)
		return 0;

	if (!cIO.FindInVector(nClassDefault, vClasses))
		return 0;

	bool bOK = false;
	map<vector<bool>, vector<uint> >::iterator iTrain;
	for (iTrain = mTrainGray.begin(); iTrain != mTrainGray.end(); iTrain++)						// have to check every element in the training set
	{
		vector<bool> vLeftTrainBase2 = BoundedBase2(bOK, vLowerBoundBase2, vUpperBoundBase2, cGC.GrayToBase2(iTrain->first));
		vector<bool> vLeftTrainGray = cGC.Base2ToGray(vLeftTrainBase2);

		if (bOK)
		{
			vector<uint> vTrainTempIndexes;
			vector<uint> vTrainTempClasses;

			nMinSum = cMOS.XORPointClassification(nIndexPosition, nClassPosition, vTrainTempIndexes, vTrainTempClasses, vLeftTrainGray, mTrainGray);
			bReturn = cMOS.UpDateVectors(nTotalClasses, nMinSum, vTrainTempIndexes, vTrainTempClasses, vMinSums, vIndexes, vClasses);
			if (!bMinClassification)								// else keep going looking for a better match for every class - have to check every member of the training set
			{
				if (!cIO.FindInVector(nClassDefault, vClasses))		// have a match for every class so stop looking further
					return 0;
			}
		}
		else
		{
			cout << "\n***Error: Failed Intervals::CalculateIntervalClassesAllSums - This should not occur.***\n";
		}
	}
	return 0;
}
// ***
uint Intervals::CalculateIntervalClassesSameSums(bool bMinClassification, vector<uint> vTargetSumsLower, vector<uint> vTargetSumsUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nClassDefault, vector<uint>& vMinSums, vector<uint>& vIndexes, vector<uint>& vClasses, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vLowerBoundBase2, vector<bool> vUpperBoundBase2, map<vector<bool>, vector<uint>> mTrainGray)
{
	IO cIO = IO();
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	vector<uint> vTempIndexes;
	vector<uint> vTempClasses;

	bool bOK = false;
	bool bReturn = false; 
	uint nMinSum = (uint)vLowerBoundBase2.size();

	vector<bool> vLowerBoundBase2SameSums = cGC.ConfigureBase2ToSameSums(bOK, vTargetSumsLower, vTargetSumsUpper, vGrayStart, vGraySize, vLowerBoundBase2);// this is necessary because "Intervals::BoundedBase2" below does not include vLowerBoundBase2

	//cout << cGC.Base2Sum(vLowerBoundBase2SameSums) << " ";
	
	if (bOK && vLowerBoundBase2 <= vLowerBoundBase2SameSums && vLowerBoundBase2SameSums < vUpperBoundBase2)
	{
		vector<bool> vLowerBoundGraySameSums = cGC.Base2ToGray(vLowerBoundBase2SameSums);
	
		vector<uint> vTrainTempIndexes;
		vector<uint> vTrainTempClasses;
		nMinSum = cMOS.XORPointClassification(nIndexPosition, nClassPosition, vTrainTempIndexes, vTrainTempClasses, vLowerBoundGraySameSums, mTrainGray);
		bReturn = cMOS.UpDateVectors(nTotalClasses, nMinSum, vTrainTempIndexes, vTrainTempClasses, vMinSums, vIndexes, vClasses);
		if (!bMinClassification)								// else keep going looking for a better match for every class
		{
			if (!cIO.FindInVector(nClassDefault, vClasses))		// have a match for every class so stop looking further
				return 0;
		}

		//cout << cGC.Base2Sum(vLowerBoundBase2SameSums) << " " << nMinSum << " ";

		//for (uint n = 0; n < vMinSums.size(); n++)
		//{
		//	cout << vMinSums[n] << " " << vClasses[n] << " ";
		//}
		//cout << "\n";
	}

	if (cGC.IncrementBase2(vLowerBoundBase2) == vUpperBoundBase2)
		return 0;

	if (!cIO.FindInVector(nClassDefault, vClasses))
		return 0;

	if (cGC.Base2Sum(vLowerBoundBase2) == 0 || (cGC.Base2Sum(vLowerBoundBase2) == 1 && cGC.GraySum(vLowerBoundBase2) == 1))		// '1' in LSD
	return 0;	//  all zeros - origin - ok

	map<vector<bool>, vector<uint> >::iterator iTrain;
	for (iTrain = mTrainGray.begin(); iTrain != mTrainGray.end(); iTrain++)						// have to check every element in the training set to generate the look-up table
	{
		bool bOK = false;
		vector<bool> vTrainBase2 = cGC.GrayToBase2(iTrain->first);
		vTrainBase2 = BoundedBase2(bOK, vLowerBoundBase2, vUpperBoundBase2, vTrainBase2);	
		vTrainBase2 = cGC.ConfigureBase2ToSameSums(bOK, vTargetSumsLower, vTargetSumsUpper, vGrayStart, vGraySize, vTrainBase2);
		
		//cout << cGC.Base2Sum(vTrainBase2) << " ";
		
		if (bOK && vLowerBoundBase2 <= vTrainBase2 && vTrainBase2 < vUpperBoundBase2)
		{

			//cout << cGC.Base2Sum(vTrainBase2) << " ";

			vector<bool> vTrainGray = cGC.Base2ToGray(vTrainBase2);

			vector<uint> vTrainTempIndexes;
			vector<uint> vTrainTempClasses;
			nMinSum = cMOS.XORPointClassification(nIndexPosition, nClassPosition, vTrainTempIndexes, vTrainTempClasses, vTrainGray, mTrainGray);

			//cout << nMinSum << " " << vMinSums[7] << "\t";
			
			bReturn = cMOS.UpDateVectors(nTotalClasses, nMinSum, vTrainTempIndexes, vTrainTempClasses, vMinSums, vIndexes, vClasses);
			if (!bMinClassification)								// else keep going looking for a better match for every class
			{
				if (!cIO.FindInVector(nClassDefault, vClasses))		// have a match for every class so stop looking further
					return 0;
			}
		}
	}
	return 1;
}

uint Intervals::CalculateMapClassesAllSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool>& vFirst, vector<bool>& vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	cout << "\nClassify Map Classes All Sums, Size = " << m.size() << "\n";

	uint nModulo = 1000;
	if (m.size() < 2001)
	{
		nModulo = 100;
	}

	vFirst.clear();
	vLast.clear();
	map<vector<bool>, vector<uint>>::iterator i;
	map<vector<bool>, vector<uint>>::iterator iNext;
	uint nCount = 0;
	for (i = m.begin(); i != m.end(); i++)
	{
		if (i == m.begin())
		{
			vFirst = i->first;
		}

		iNext = i;
		iNext++;
		if (iNext != m.end())
		{
			vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
			vector<uint> vIndexes(nTotalClasses, nIndexDefault);
			vector<uint> vClasses(nTotalClasses, nClassDefault);

			uint nReturn = CalculateIntervalClassesAllSums(bMinClassification, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, i->first, iNext->first, mTrainGray);

			if (bPrintSumsAndIndexes)
			{
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
				i->second = vMinSums;
			}
			else
			{
				i->second = vClasses;
			}
		}
		else
		{
			vLast = i->first;
		}

		nCount++;
		if (nCount % nModulo == 0)
			cout << nCount << " ";
	}
	return 0;
}

uint Intervals::CalculateMapClassesSameSumsSizeOne(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, vector<uint> vGraySumLower, vector<uint> vGraySumUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool>& vFirst, vector<bool>& vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	cout << "\nClassify Map Classes Same Sums, Size = " << m.size() << "\n";

	map<vector<bool>, vector<uint>>::iterator i;
	i = m.begin();
	vFirst = i->first;
	vLast = i->first;

	vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
	vector<uint> vIndexes(nTotalClasses, nIndexDefault);
	vector<uint> vClasses(nTotalClasses, nClassDefault);

	bool bReturn = cMOS.XORPointClassificationAndUpDateVectors(nTotalClasses, nIndexPosition, nClassPosition, vMinSums, vIndexes, vClasses, cGC.Base2ToGray(i->first), mTrainGray);

	if (bPrintSumsAndIndexes)
	{
		vMinSums.push_back(999999);
		vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
		vMinSums.push_back(999999);
		vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
		i->second = vMinSums;
	}
	else
	{
		i->second = vClasses;
	}

	if (!bReturn)
	{
		cout << "\n***Error: Intervals::CalculateMapClassesSameSums***\n";
		return 2;
	}

	return 0;
}

uint Intervals::CalculateMapClassesSameSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, vector<uint> vGraySumLower, vector<uint> vGraySumUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool>& vFirst, vector<bool>& vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	GrayCode cGC = GrayCode();
	MeasureOfSimilarity cMOS = MeasureOfSimilarity();

	vFirst.clear();
	vLast.clear();
	map<vector<bool>, vector<uint>>::iterator i;
	map<vector<bool>, vector<uint>>::iterator iNext;
	uint nCount = 0;

	if (m.size() == 1)
	{
		return CalculateMapClassesSameSumsSizeOne(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vFirst, vLast, m, mTrainGray);
	}

	cout << "\nClassify Map Classes Same Sums, Size = " << m.size() << "\n";

	uint nModulo = 1000;
	if (m.size() < 2001)
	{
		nModulo = 100;
	}

	for (i = m.begin(); i != m.end(); i++)
	{
		if (i == m.begin())
		{
			vFirst = i->first;
		}

		iNext = i;
		iNext++;
		if (iNext != m.end())
		{
			uint nDepth = 0;
			vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
			vector<uint> vIndexes(nTotalClasses, nIndexDefault);
			vector<uint> vClasses(nTotalClasses, nClassDefault);

			uint nReturn = CalculateIntervalClassesSameSums(bMinClassification, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, i->first, iNext->first, mTrainGray);


			//for (uint n = 0; n < vMinSums.size(); n++)
			//{
			//	cout << vMinSums[n] << " ";
			//}
			//cout << "\t\t";

		
			if (bPrintSumsAndIndexes)
			{
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
				i->second = vMinSums;
			}
			else
			{
				i->second = vClasses;
			}
		}
		else
		{
			vLast = i->first;
		}

		nCount++;
		if (nCount % nModulo == 0)
			cout << nCount << " ";
	}
	return 0;
}

bool Intervals::UpDatePrevMapClassesAllSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vFirst, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	map<vector<bool>, vector<uint>>::iterator iFind;
	map<vector<bool>, vector<uint>>::iterator iPrev;
	iFind = m.find(vFirst);
	if (iFind != m.end() && iFind != m.begin())
	{
		iPrev = iFind;
		iPrev--;

		uint nDepth = 0;
		vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
		vector<uint> vIndexes(nTotalClasses, nIndexDefault);
		vector<uint> vClasses(nTotalClasses, nClassDefault);

		uint nReturn = CalculateIntervalClassesAllSums(bMinClassification, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, iPrev->first, iFind->first, mTrainGray);

		if (bPrintSumsAndIndexes)
		{
			vMinSums.push_back(999999);
			vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
			vMinSums.push_back(999999);
			vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
			iPrev->second = vMinSums;
		}
		else
		{
			iPrev->second = vClasses;
		}
		return true;
	}
	return false;
}

bool Intervals::UpDateLastMapClassesAllSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	map<vector<bool>, vector<uint>>::iterator iFind;
	map<vector<bool>, vector<uint>>::iterator iNext;
	iFind = m.find(vLast);
	if (iFind != m.end())
	{
		iNext = iFind;
		iNext++;
		if (iNext != m.end())
		{
			uint nDepth = 0;
			vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
			vector<uint> vIndexes(nTotalClasses, nIndexDefault);
			vector<uint> vClasses(nTotalClasses, nClassDefault);
			uint nReturn = CalculateIntervalClassesAllSums(bMinClassification, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, iFind->first, iNext->first, mTrainGray);

			if (bPrintSumsAndIndexes)
			{
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
				iFind->second = vMinSums;
			}
			else
			{
				iFind->second = vClasses;
			}
			return true;
		}
	}
	return false;
}

bool Intervals::UpDatePrevAndLastMapClassesAllSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vFirst, vector<bool> vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	if (!UpDatePrevMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vFirst, m, mTrainGray))
	{
		return false;
	}
	if (!UpDateLastMapClassesAllSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, nTotalClasses, nIndexPosition, nClassPosition, vLast, m, mTrainGray))
	{
		return false;
	}
	return true;
}

bool Intervals::UpDatePrevMapClassesSameSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, vector<uint> vGraySumLower, vector<uint> vGraySumUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vFirst, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	map<vector<bool>, vector<uint>>::iterator iFind;
	map<vector<bool>, vector<uint>>::iterator iPrev;
	iFind = m.find(vFirst);
	if (iFind != m.end() && iFind != m.begin())
	{
		iPrev = iFind;
		iPrev--;

		uint nDepth = 0;
		vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
		vector<uint> vIndexes(nTotalClasses, nIndexDefault);
		vector<uint> vClasses(nTotalClasses, nClassDefault);

		uint nReturn = CalculateIntervalClassesSameSums(bMinClassification, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, iPrev->first, iFind->first, mTrainGray);

		if (bPrintSumsAndIndexes)
		{
			vMinSums.push_back(999999);
			vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
			vMinSums.push_back(999999);
			vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
			iPrev->second = vMinSums;
		}
		else
		{
			iPrev->second = vClasses;
		}
		return true;
	}
	return false;
}

bool Intervals::UpDateLastMapClassesSameSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, vector<uint> vGraySumLower, vector<uint> vGraySumUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	map<vector<bool>, vector<uint>>::iterator iFind;
	map<vector<bool>, vector<uint>>::iterator iNext;
	iFind = m.find(vLast);
	if (iFind != m.end())
	{
		iNext = iFind;
		iNext++;
		if (iNext != m.end())
		{
			uint nDepth = 0;
			vector<uint> vMinSums(nTotalClasses, nMinSumDefault);
			vector<uint> vIndexes(nTotalClasses, nIndexDefault);
			vector<uint> vClasses(nTotalClasses, nClassDefault);
			uint nReturn = CalculateIntervalClassesSameSums(bMinClassification, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nClassDefault, vMinSums, vIndexes, vClasses, nTotalClasses, nIndexPosition, nClassPosition, iFind->first, iNext->first, mTrainGray);

			if (bPrintSumsAndIndexes)
			{
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vIndexes.begin(), vIndexes.end());
				vMinSums.push_back(999999);
				vMinSums.insert(vMinSums.end(), vClasses.begin(), vClasses.end());
				iFind->second = vMinSums;
			}
			else
			{
				iFind->second = vClasses;
			}
			return true;
		}
	}
	return false;
}

bool Intervals::UpDatePrevAndLastMapClassesSameSums(bool bPrintSumsAndIndexes, bool bMinClassification, uint nMinSumDefault, uint nIndexDefault, uint nClassDefault, vector<uint> vGraySumLower, vector<uint> vGraySumUpper, vector<uint> vGrayStart, vector<uint> vGraySize, uint nTotalClasses, uint nIndexPosition, uint nClassPosition, vector<bool> vFirst, vector<bool> vLast, map<vector<bool>, vector<uint>>& m, map<vector<bool>, vector<uint>> mTrainGray)
{
	if (!UpDatePrevMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vFirst, m, mTrainGray))
	{
		return false;
	}
	if (!UpDateLastMapClassesSameSums(bPrintSumsAndIndexes, bMinClassification, nMinSumDefault, nIndexDefault, nClassDefault, vGraySumLower, vGraySumUpper, vGrayStart, vGraySize, nTotalClasses, nIndexPosition, nClassPosition, vLast, m, mTrainGray))
	{
		return false;
	}
	return true;
}


