public ParallelSmoFanSolver2(Problem <TProblemElement> problem, IKernel <TProblemElement> kernel, float C) : base(problem, kernel, C) { //todo: add checking if kernel is initialized //remeber that we have variable kernel in base class Q = new CachedKernel <TProblemElement>(problem, kernel); //get diagonal cache, kernel should compute that QD = Q.GetQD(); //Shrinking = false; //todo: change it, add array to base class with different penalty for labels Cp = C; Cn = C; problemSize = problem.ElementsCount; numberOfThreads = Environment.ProcessorCount; rangeSize = (int)Math.Ceiling((problemSize + 0.0) / numberOfThreads); partition = Partitioner.Create(0, problemSize, rangeSize); resetEvents = new ManualResetEvent[numberOfThreads]; //max data structures maxPairsWaitCallbacks = new WaitCallback[numberOfThreads]; //data for finding maxPair in svm solver maxPairThreadsData = new MaxFindingThreadData[numberOfThreads]; maxPairs = new Pair <int, float> [numberOfThreads]; //min data structures minPairsWaitCallbacks = new WaitCallback[numberOfThreads]; //data for finding minPair in svm solver minPairThreadsData = new MinFindingThreadData[numberOfThreads]; minPairs = new Pair <int, float> [numberOfThreads]; //int startRange = 0; //int endRange = startRange + rangeSize; Tuple <int, int>[] ranges = ListHelper.CreateRanges(problemSize, numberOfThreads); for (int i = 0; i < numberOfThreads; i++) { resetEvents[i] = new ManualResetEvent(false); maxPairs[i] = new Pair <int, float>(-1, float.NegativeInfinity); maxPairThreadsData[i] = new MaxFindingThreadData() { ResetEvent = resetEvents[i], Pair = maxPairs[i], //Range = new Tuple<int, int>(startRange, endRange) Range = ranges[i] }; maxPairsWaitCallbacks[i] = new WaitCallback(this.FindMaxPairInThread); minPairs[i] = new Pair <int, float>(-1, float.PositiveInfinity); minPairThreadsData[i] = new MinFindingThreadData() { ResetEvent = resetEvents[i], Pair = minPairs[i], //Range = new Tuple<int, int>(startRange, endRange) Range = ranges[i] }; minPairsWaitCallbacks[i] = new WaitCallback(this.FindMinPairInThread); //change the range //startRange = endRange; //int rangeSum = endRange + rangeSize; //endRange = rangeSum < problemSize ? rangeSum : problemSize; } }
/// <summary> /// finds min 'j' in svm solver, its called in separate thread /// and find it in specific range of array /// </summary> /// <param name="threadData"></param> private void FindMinPairInThread(object threadData) { MinFindingThreadData data = (MinFindingThreadData)threadData; Pair <int, float> localMaxMin = data.Pair; float GMax2 = float.NegativeInfinity; int i = data.GMaxIdx; float obj_diff = 0; float quad_coef = 0; float grad_diff = 0; for (int j = data.Range.Item1; j < data.Range.Item2; j++) { if (y[j] == +1) { if (!is_lower_bound(j)) { grad_diff = data.GMax + G[j]; //save max value if (G[j] >= GMax2) { GMax2 = G[j]; } if (grad_diff > 0) { quad_coef = (float)(data.Q_i[i] + QD[j] - 2.0 * y[i] * data.Q_i[j]); if (quad_coef > 0) { obj_diff = -(grad_diff * grad_diff) / quad_coef; } else { obj_diff = (float)(-(grad_diff * grad_diff) / 1e-12); } if (obj_diff < localMaxMin.Second) { localMaxMin.First = j; localMaxMin.Second = obj_diff; } } } } else { if (!is_upper_bound(j)) { grad_diff = data.GMax - G[j]; //save -max if (-G[j] >= GMax2) { GMax2 = -G[j]; } if (grad_diff > 0) { quad_coef = (float)(data.Q_i[i] + QD[j] + 2.0 * y[i] * data.Q_i[j]); if (quad_coef > 0) { obj_diff = -(grad_diff * grad_diff) / quad_coef; } else { obj_diff = (float)(-(grad_diff * grad_diff) / 1e-12); } if (obj_diff < localMaxMin.Second) { localMaxMin.First = j; localMaxMin.Second = obj_diff; } } } } } data.GMax2 = GMax2; //signal for thread that computation complete data.ResetEvent.Set(); }