bool insert_keep_sorted_and_unique(typename VECTOR::value_type p, VECTOR& procs) { typename VECTOR::iterator iter = std::lower_bound(procs.begin(), procs.end(), p); if (iter == procs.end() || *iter != p) { procs.insert(iter, p); return true; } return false; }
//------------------------------------------------------------------------- // Jenks' Optimization Method // //------------------------------------------------------------------------- void MgFeatureNumericFunctions::GetJenksCategories( VECTOR &inputData, int numPartsRequested, double dataMin, double dataMax, VECTOR &distValues ) { // numPartsRequested // 2 - 10; 5 is good int i = 0; // index for numObservations (may be very large) int j = 0; // index for numPartsRequested (about 4-8) int k = 0; // Sort the data values in ascending order std::sort(inputData.begin(), inputData.end()); int numObservations = (int)inputData.size(); // may be very large // Possible improvement: Rework the code to use normal 0 based arrays. // Actually it doesn't matter much since we have to create two // matrices that themselves use more memory than the local copy // of inputData. // // In order to ease the use of original FORTRAN and the later BASIC // code, I will use 1 origin arrays and copy the inputData into // a local array; // I'll dimension the arrays one larger than necessary and use the // index values from the original code. // // The algorithm must calculate with floating point values. // If more optimization is attempted in the future, be aware of // problems with calculations using mixed numeric types. std::vector<double> data; data.push_back(0); // dummy value at index 0 std::copy(inputData.begin(), inputData.end(), std::back_inserter(data)); // copy from parameter inputData so that data index starts from 1 // Note that the Matrix constructors initialize all values to 0. // mat1 contains integer values used for indices into data // mat2 contains floating point values of data and bigNum MgMatrix<int> mat1(numObservations + 1, numPartsRequested + 1); MgMatrix<double> mat2(numObservations + 1, numPartsRequested + 1); // const double bigNum = 1e+14; // from original BASIC code; // const double bigNum = std::numeric_limits<double>::max(); const double bigNum = DBL_MAX; // compiler's float.h for (i = 1; i <= numPartsRequested; ++i) { mat1.Set(1, i, 1); for (j = 2; j <= numObservations; ++j) { mat2.Set(j, i, bigNum); } } std::vector<int> classBounds; classBounds.push_back(-2); // dummy value for (i = 1; i <= numPartsRequested; ++i) { classBounds.push_back(-1); } for (int L = 2; L <= numObservations; ++L) { double s1 = 0; double s2 = 0; double v = 0; int w = 0; for (int m = 1; m <= L; ++m) { int i3 = L - m + 1; double val = data[i3]; s2 += (double(val) * double(val)); // if datatype of val is ever allowed to be same as template // parameter T, make sure multiplication is done in double. s1 += val; ++w; v = s2 - ((s1 * s1) / w); int i4 = i3 - 1; if (i4 > 0) { for (j = 2; j <= numPartsRequested; ++j) { double tempnum = v + mat2.Get(i4, j - 1); if (double(mat2.Get(L, j)) >= tempnum) { mat1.Set(L, j, i3); mat2.Set(L, j, tempnum); } } } } mat1.Set(L, 1, 1); mat2.Set(L, 1, v); } k = numObservations; for (j = numPartsRequested; j >= 1; --j) { if (k >= 0 && k <= numObservations) { classBounds[j] = mat1.Get(k, j); k = mat1.Get(k, j) - 1; } } std::vector<int> indices; indices.push_back(0); for (i = 2; i <= numPartsRequested; ++i) { int index = classBounds[i] - 1; if (index > indices.back()) { indices.push_back(index); } } FixGroups(inputData, indices); double val = 0.0; int index = 0; int totIndex = (int)indices.size(); for (int i = 1; i < totIndex; ++i) { index = indices[i] - 1; val = inputData[index]; distValues.push_back(val); } index = numObservations - 1; val = inputData[index]; distValues.push_back(val); int retCnt = (int)distValues.size(); int inCnt = (int)inputData.size(); if (retCnt > 0 && inCnt > 0) { if (!doubles_equal(distValues[0],inputData[0])) { distValues.insert(distValues.begin(), inputData[0]); } } return; }