//Method starting all the calculations (i.e., calling the corresponding method in the Combinatorics class) public Results startCalcs(List<Input> inputCols, int indepIndex, FitConfig curFitConfig) { Combinatorics curCombinatorics = new Combinatorics(); Results curResults = new Results(); curResults.allInputs = inputCols; curResults.config = new Config(); curResults.config.operations.Add(Operation.Addition); curResults.config.exponents = createListExponents(); curResults.config.maxNoCombs = 20; curResults.config.fitConfig = curFitConfig; //Due to the huge amount of (potential) information to be managed, the a-apriori logical structure "combinations -> calculations (regressions) -> analysis" is not present. //Both calculations and analysis are performed for each single combination and only the "good-enough" ones are kept in memory curResults = curCombinatorics.startCombinatorics(curResults, indepIndex); curResults.combinations = curResults.combinations.OrderByDescending(x => x.assessment.globalRating).ThenBy(x => x.averError).ThenBy(x => x.independentVar.input.displayedName).ThenBy(x => x.dependentVars.items.Count).ToList(); return curResults; }
//Method called every time the calculations are completed (in any case: after finding valid trends or not) to write the results to the output file public void writeOutputs(Results curResults) { try { using (StreamWriter sw = new StreamWriter(Environment.CurrentDirectory + @"\outputs.csv")) { StringBuilder sb = new StringBuilder(); sb.Append("No.,"); sb.Append("Independent variable,"); sb.Append("Dependent variable,"); sb.Append("Polynomial coefficients (A|B|C),"); sb.Append("Reliability for the expected accuracy,"); sb.Append("In-sample average error (%),"); sb.Append("Total time,"); sb.Append("Expected accuracy,"); sb.Append("Output equation"); sw.WriteLine(sb.ToString()); //Loop iterating through all the valid solutions and printing out the required information for each of them int count = 0; foreach (ValidCombination comb in curResults.combinations) { count = count + 1; sb = new StringBuilder(); sb.Append(count.ToString() + ","); sb.Append("[" + comb.independentVar.input.name + "],"); sb.Append(createCombinationString(comb) + ","); sb.Append(comb.coeffs.A.ToString(Common.curCulture) + "|" + comb.coeffs.B.ToString(Common.curCulture) + "|" + comb.coeffs.C.ToString(Common.curCulture) + ","); sb.Append(comb.assessment.globalRating.ToString("N2", Common.curCulture) + ","); sb.Append((100 * comb.averError).ToString("N2", Common.curCulture)); if (count == 1) { sb.Append("," + curResults.totTime + ","); sb.Append(curResults.config.fitConfig.expectedAccuracy.ToString().ToUpper() + ","); sb.Append("[independent]=A+B*[dependent]+C*[dependent]^2"); } sw.WriteLine(sb.ToString()); } } } catch { MessageBox.Show("There was an error while writing the results to \"outputs.csv\""); } }
//Method starting the whole combinatorics process (and, subsequently, the calculations one) for the given independent variable and all the remaining "Input" (columns) private Results mainCombinations(Results curResults, List<Input> inputs, Variable indepVar) { //Loop accounting for combinations consisting in just one variable for (int col = 0; col < inputs.Count; col++) { if (cancelSim) return curResults; if (col != indepVar.index) curResults.combinations = addCombination(inputs, new List<int> { col }, curResults.config, curResults.combinations, indepVar); } //Main loop combining all the variables among them, together with all the exponents and operations for (int col = 0; col < inputs.Count - 1; col++) //All the columns from the start until the previous to the last one { if (cancelSim) return curResults; if (col == indepVar.index) continue; MainCalcs.bgwMain.ReportProgress(0, "Independent variable: " + indepVar.input.displayedName + " - Analysing all the combinations involving: " + inputs[col].displayedName + Environment.NewLine + "Valid solutions so far: " + curResults.combinations.Count.ToString()); for (int col2 = col; col2 < inputs.Count; col2++) //All the columns from "col" to the last one { if (cancelSim) return curResults; if (col2 == indepVar.index) continue; int maxComb = inputs.Count - 1 - col2; for (int comb = 0; comb < maxComb; comb++) // All the combinations of columns. For example: with 1, 2, 3, 4, when col is 1, there are upto 3 (e.g., 2-3-4) { if (cancelSim) return curResults; int col3 = col2; List<int> curList = new List<int>(); curList.Add(col); for (int comb2 = 0; comb2 <= comb; comb2++) { col3 = col3 + 1; if (col3 != indepVar.index) { curList.Add(col3); //List including the variables being accounted in the current combination } } curResults.combinations = addCombination(inputs, curList, curResults.config, curResults.combinations, indepVar); } } } return curResults; }
//Starting the combination process under the input conditions, but also the subsequent calculations (as explained in the comments above) public Results startCombinatorics(Results curResults, int indepIndex) { if (indepIndex == -1) { //The user hasn't specified any independent (to-be-predicted) variable: all the columns have to be analysed, such that the most adequate one can be found for (int col = 0; col < curResults.allInputs.Count; col++) { double commonRatio = (double)curResults.allInputs[col].preAnalysis.commonValsCount / (double)curResults.allInputs[col].vals.Count; if (commonRatio < 0.75) //Predicting the values of an almost-constant variable wouldn't make too much sense { curResults = combsForIndep(curResults.allInputs, col, curResults); } else { MainCalcs.bgwMain.ReportProgress(0, "Independent variable: " + curResults.allInputs[col].displayedName + " - SKIPPED"); System.Threading.Thread.Sleep(100); } if (cancelSim) break; } } else { //Only one independent variable ("indepIndex") will be considered curResults = combsForIndep(curResults.allInputs, indepIndex, curResults); } return curResults; }
//This method creates a new "Variable" instance for the given independent variable (y) from the original "Input" one and starts the combinating/calculating processes private Results combsForIndep(List<Input> allInputs, int curIndex, Results curResults) { int maxDec = allInputs[curIndex].vals.Max(x => x <= Int32.MaxValue ? ((decimal)x - Convert.ToInt32((decimal)x)).ToString().Length - 2 : 0); if (maxDec < 0) maxDec = 0; Variable indepVar = new Variable { index = curIndex, input = allInputs[curIndex], noDec = maxDec }; return mainCombinations(curResults, allInputs, indepVar); }