/// <summary> /// This method will compute any possible possibilities for the next split (predictions), /// will make some stats on it, and then take a decision to keep the best one /// </summary> /// <param name="splitIndex">split index (starting from 0)</param> /// <param name="prevMostPopSof">Most Populated class SoF of the previous split</param> /// <returns></returns> private Data.PredictionOfSplits ComputeFieldPredictionsAndKeepTheBest(int splitIndex, int prevMostPopSof) { // remaining class car queues which contains cars in it var availableQueues = (from r in classesQueues where r.CarsCount > 0 select r).ToList(); int remainingQueues = availableQueues.Count; // enum classes ids var availableClassesId = (from r in availableQueues select r.CarClassId).ToList(); // Get the Truth Table of any possibile combinations for the current split (splitIndex) Calc.EveryCombinations combS = new EveryCombinations(availableClassesId); // Get anothe Truth Table of any possibile combinations for the next split (splitIndex+1) Calc.EveryCombinations combNS = new EveryCombinations(availableClassesId); // generate all possible predictions List <PredictionOfSplits> predictions = new List <PredictionOfSplits>(); foreach (var cS in combS.Combinations) { foreach (var cNS in combNS.Combinations) { if (cNS.NumberOfTrue >= remainingQueues) { PredictionOfSplits prediction = new PredictionOfSplits(); prediction.CurrentSplit = GenerateSplitFromCombination(splitIndex + 1, cS); prediction.NextSplit = GenerateSplitFromCombination(splitIndex + 2, cNS, prediction.CurrentSplit); if (prediction.CurrentSplit.TotalCarsCount > 0 && prediction.NextSplit.TotalCarsCount > 0) { predictions.Add(prediction); } } } } // calc stats of all predictions List <PredictionOfSplits> predictions2 = new List <PredictionOfSplits>(); // a new list foreach (var prediction in predictions) // for each existing prediction { prediction.CalcStats(prevMostPopSof); // calc stats predictions2.Add(prediction); // add it to a new list if (ParameterRatingThresholdValue > 0) // it the iRating split option is enabled { // compute another prediction with cutting the split var variations = prediction.CuttedVariation(ParameterRatingThresholdValue, prevMostPopSof, minCarsToHalfSplits); if (variations != null && variations.Count > 0) { predictions2.AddRange(variations); // if available, add this new predictions to the list } } } if (predictions2.Count == 0) { return(null); } // Choose the best now prediction PredictionsEvaluator eval = new PredictionsEvaluator(predictions2, classesQueues, ParameterMaxSofDiffValue, ParameterMaxSofFunctStartingIRValue, ParameterMaxSofFunctStartingThreshold, ParameterMaxSofFunctExtraThresoldPerK, ParameterTopSplitExceptionValue, ParameterDebugFileValue, ParameterNoMiddleClassesEmptyValue); PredictionOfSplits bestScenario = eval.GetBest(); return(bestScenario); }
public void Compute(List <Line> data, int fieldSize) { if (ParameterDebugFileValue == 1) { PredictionsEvaluator.CleanOldDebugFiles(); } minCarsToHalfSplits = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(ParameterMinCarsValue) / 2d)); // Calc number of splits required // And try to reduce fieldSize, if possible, for the same number of splits numberOfSplits = Tools.DivideAndCeil(data.Count, fieldSize); int betterFieldSize = Tools.DivideAndCeil(data.Count, numberOfSplits); this.fieldSize = Math.Min(fieldSize, betterFieldSize); // create classes queues classesQueues = Tools.SplitCarsPerClass(data); classesIds = (from r in classesQueues select r.CarClassId).ToList(); // instanciate an ClassicAffineDistributio algorithm to use its car distribution system affineDistributor = new ClassicAffineDistribution(); affineDistributor.ParameterMinCarsValue = this.ParameterMinCarsValue; affineDistributor.SetFieldSize(fieldSize); affineDistributor.InitData(classesIds, data); if (classesQueues.Count == 1) { // if only one class, the affinedistributor will do the job affineDistributor.Compute(data, fieldSize); Splits = affineDistributor.Splits; return; } // Starting the process Splits = new List <Split>(); // this variable will contain the SoF Max of the 'Most Populated Class' of the last split // it will be given to the next one to help evaluating possible situations int prevMaxPopSof = -1; // for each split required for (int i = 0; i < numberOfSplits; i++) { // call the prediction algorithm, and get the best situation var prediction = ComputeFieldPredictionsAndKeepTheBest(i, prevMaxPopSof); // if something is possible if (prediction != null) { // Create the split, for true. Implement(prediction); // remember the Max SoF of the 'Most Populated Class' prevMaxPopSof = prediction.CurrentSplit.GetMaxClassSof(); } } // create the last split ... var lastsplit = Splits.Last(); // by checking any class queues for (int i = 0; i < classesQueues.Count; i++) { // if any cars are still in the queue var cars = classesQueues[i].PickCars(classesQueues[i].CarsCount); if (cars.Count > 0) { // put them in this last split if (lastsplit.GetClassId(i) == 0) { lastsplit.SetClass(i, classesIds[i]); } lastsplit.AppendClassCars(i, cars); } } // call the optimizer process (second pass algorithm) for // rounding cars number between splits, or fix some issue // if some splits exceed the fieldsize classesQueues = Tools.SplitCarsPerClass(data); SplitsRepartitionOptimizer optimizer = new SplitsRepartitionOptimizer(Splits, fieldSize, classesIds, classesQueues, affineDistributor); Splits = optimizer.OptimizeAndSolveDifferences(); // now we have the final result }