//this is asych for the calling Task.WhenAll //but does not necessarily need internal asych awaits public async Task <bool> RunAlgorithmAsync(List <List <double> > data) { bool bHasCalculations = false; try { //minimal data requirement is first five cols if (_colNames.Count() < 5 || _mathTerms.Count() == 0) { ErrorMessage = "Complete randomized anova requires at least 1 dependent variable and 1 independent variable. Randomized block and factorial anovas require at least 2 independent variables."; return(bHasCalculations); } if (data.Count() < 5) { //185 same as other analysis ErrorMessage = "Anova requires at least 2 rows of observed data and 3 rows of scoring data."; return(bHasCalculations); } //convert data to a Math.Net Matrix //last 3 rows are used to generate ci List <List <double> > dataci = data.Skip(data.Count - _scoreRows).ToList(); data.Reverse(); List <List <double> > dataobs = data.Skip(_scoreRows).ToList(); dataobs.Reverse(); //actual observed values Vector <double> y = Shared.GetYData(dataobs); //treatments or factor1 levels Matrix <double> treatments = Shared.GetDistinctMatrix(dataobs, 1); //206 condition added due to M and E dataset indexing _totalsNeeded = treatments.ColumnCount; double tDF = treatments.ColumnCount - 1; //step 1. get total of observed data double yTotal = y.Sum(); //step 2. get total of observed data squared double yTotal2 = y.PointwisePower(2).Sum(); //step 3. set CM double CM = Math.Pow(yTotal, 2) / y.Count(); //step 4. treatments and blocks double SSTotal = yTotal2 - CM; //add the data to a string builder StringBuilder sb = new StringBuilder(); sb.AppendLine("anova results"); //5 col array string[] cols = new string[] { "source", "df", "SS", "MS", "F" }; sb.AppendLine(Shared.GetLine(cols, true)); List <List <double> > totals = new List <List <double> >(_totalsNeeded); //min treatment block required bool bIsBlock = (_depColNames.Contains("treatment") && _depColNames.Contains("block")) ? true : false; //min 2 factors required bool bIsFactorial = (_depColNames.Contains("factor1") && _depColNames.Contains("factor2")) ? true : false; bool bIsComplete = (bIsBlock == false && bIsFactorial == false) ? true : false; if (bIsComplete) { double eDF = y.Count() - treatments.ColumnCount; //step 5.treatments (correct to divide by rows) double SST = ((treatments.ColumnSums().PointwisePower(2).Sum()) / treatments.RowCount) - CM; //step 6. error double SSE = SSTotal - SST; //step 7. mean treatment double MST = SST / tDF; //step 8. mean error double MSE = SSE / (y.Count() - treatments.ColumnCount); //step 9. F treatments double FT = MST / MSE; //tests double s = Math.Pow(MSE, 0.5); //correct 2 tailed t test int itDF = CalculatorHelpers.ConvertStringToInt(tDF.ToString()); int ieDF = CalculatorHelpers.ConvertStringToInt(eDF.ToString()); double dbCI = CalculatorHelpers.GetConfidenceIntervalProb(_confidenceInt); //TINV divides dbCI by 2 to get student t double tCriticalValue = ExcelFunctions.TInv(dbCI, ieDF); //prevents an error in Finv if (itDF == 0) { itDF = 1; } double FCriticalTValue = ExcelFunctions.FInv(dbCI, itDF, ieDF); string FTGreaterFCritical = (FT > FCriticalTValue) ? "true" : "false"; for (int i = 0; i < _totalsNeeded; i++) { //206 condition added due to M and E dataset indexing if (i < treatments.ColumnCount) { SetAnovaIntervals(i, totals, treatments, tCriticalValue, s, CalculatorHelpers.ConvertStringToDouble(treatments.RowCount.ToString()), FT, FCriticalTValue, bIsComplete); } } this.DataToAnalyze.Add(Label, totals); ////add the data to a string builder cols = new string[] { "treats", itDF.ToString("F0"), SST.ToString("F4"), MST.ToString("F4"), FT.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { "error ", ieDF.ToString("F0"), SSE.ToString("F4"), MSE.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { "total ", (y.Count() - 1).ToString("F0"), (SSTotal).ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { string.Concat("F Crit ", "treats"), FCriticalTValue.ToString("F5"), "F > F Critical", FTGreaterFCritical }; sb.AppendLine(Shared.GetLine(cols, true)); } else { //observations per cell for factorials (data[0] if first row of data) double r = Shared.GetObservationsPerCell(dataobs, 1, data[0].ElementAt(1), data[0].ElementAt(2)); //blocks or factor2 levels Matrix <double> blocks = Shared.GetDistinctMatrix(dataobs, 2); double bDF = blocks.ColumnCount - 1; double eDF = y.Count() - treatments.ColumnCount - blocks.ColumnCount + 1; if (bIsFactorial) { eDF = (treatments.ColumnCount * blocks.ColumnCount) * (r - 1); } //factorial interaction df double tbDF = tDF * bDF; //step 5.treatments (correct to divide by r) double SST = ((treatments.ColumnSums().PointwisePower(2).Sum()) / (blocks.ColumnCount * r)) - CM; //step 6. blocks double SSB = ((blocks.ColumnSums().PointwisePower(2).Sum()) / (treatments.ColumnCount * r)) - CM; //factor level interaction double SSFL = 0; //step 7. error double SSE = 0; if (bIsFactorial) { double totalinteraction = Shared.GetTotalInteraction(blocks, r); //watch block.colcount for 2 x 3 factorials SSFL = (totalinteraction / r) - SST - SSB - CM; //step 7. error SSE = SSTotal - SST - SSB - SSFL; } else { //step 7. error SSE = SSTotal - SST - SSB; } //step 8. mean treatment double MST = SST / tDF; //step 9. mean block double MSB = SSB / bDF; //step 10. mean error double MSE = SSE / eDF; double MSFL = SSFL / tbDF; //step 11. F treatments double FT = MST / MSE; //step 12. F blocks double FB = MSB / MSE; double FTB = MSFL / MSE; //tests double s = Math.Pow(MSE, 0.5); //correct 2 tailed t test int itDF = CalculatorHelpers.ConvertStringToInt(tDF.ToString()); int ibDF = CalculatorHelpers.ConvertStringToInt(bDF.ToString()); int itbDF = CalculatorHelpers.ConvertStringToInt(tbDF.ToString()); int ieDF = CalculatorHelpers.ConvertStringToInt(eDF.ToString()); double dbCI = CalculatorHelpers.GetConfidenceIntervalProb(_confidenceInt); //TINV divides dbCI by 2 to get student t double tCriticalValue = ExcelFunctions.TInv(dbCI, ieDF); //prevents an error in Finv if (itDF == 0) { itDF = 1; } double FCriticalTValue = ExcelFunctions.FInv(dbCI, itDF, ieDF); string FTGreaterFCritical = (FT > FCriticalTValue) ? "true" : "false"; //prevents an error in Finv if (ibDF == 0) { ibDF = 1; } double FCriticalBValue = ExcelFunctions.FInv(dbCI, ibDF, ieDF); string FBGreaterFCritical = (FB > FCriticalBValue) ? "true" : "false"; //prevents an error in Finv if (itbDF == 0) { itbDF = 1; } double FCriticalTBValue = ExcelFunctions.FInv(dbCI, itbDF, ieDF); string FTBGreaterFCritical = (FTB > FCriticalTBValue) ? "true" : "false"; //List<List<double>> totals = new List<List<double>>(_totalsNeeded); if (bIsFactorial) { //unless custom stylesheets are developed, can only display factor 1 - factor 2 diffs //build a matrix equivalent to treatments -1 row, variable cols Matrix <double> torbs = Matrix <double> .Build.Dense(1, _totalsNeeded); List <double> mrow = new List <double>(_totalsNeeded); for (int i = 0; i < _totalsNeeded; i++) { double cellMean = Shared.GetMeanPerCell(dataobs, 1, 2, i, i, r); mrow.Add(cellMean); } torbs.SetRow(0, mrow.ToArray()); for (int i = 0; i < _totalsNeeded; i++) { //206 condition added due to M and E dataset indexing if (i < treatments.ColumnCount) { //treatments SetAnovaIntervals(i, totals, torbs, tCriticalValue, s, CalculatorHelpers.ConvertStringToDouble(blocks.ColumnCount.ToString()), FT, FCriticalTValue, bIsComplete); } } //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r); //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 1, r); //SetAnovaIntervals2(1, cell1Mean, cell2Mean, tCriticalValue, s, r); //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r); //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 2, 0, r); //SetAnovaIntervals2(2, cell1Mean, cell2Mean, tCriticalValue, s, r); //double cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r); //double cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 1, 0, r); //SetAnovaIntervals2(0, cell1Mean, cell2Mean, tCriticalValue, s, r); //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r); //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 1, r); //SetAnovaIntervals2(1, cell1Mean, cell2Mean, tCriticalValue, s, r); //cell1Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 0, 0, r); //cell2Mean = Shared.GetMeanPerCell(dataobs, 1, 2, 2, 0, r); //SetAnovaIntervals2(2, cell1Mean, cell2Mean, tCriticalValue, s, r); } else { //unless custom stylesheets are developed, need to only display treatment diffs for (int i = 0; i < _totalsNeeded; i++) { //206 condition added due to M and E dataset indexing if (i < treatments.ColumnCount) { //treatments SetAnovaIntervals(i, totals, treatments, tCriticalValue, s, CalculatorHelpers.ConvertStringToDouble(blocks.ColumnCount.ToString()), FT, FCriticalTValue, bIsComplete); ////blocks //SetAnovaIntervals(i, totals, blocks, tCriticalValue, s, // CalculatorHelpers.ConvertStringToDouble(treatments.ColumnCount.ToString()), // FB, FCriticalBValue, bIsComplete); //interactions } } } this.DataToAnalyze.Add(Label, totals); string sTreats = "treats "; string sBlocks = "blocks "; if (bIsFactorial) { sTreats = "factor1 "; sBlocks = "factor2 "; } ////add the data to a string builder //StringBuilder sb = new StringBuilder(); //sb.AppendLine("anova results"); cols = new string[] { sTreats, itDF.ToString("F0"), SST.ToString("F4"), MST.ToString("F4"), FT.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { sBlocks, bDF.ToString("F0"), SSB.ToString("F4"), MSB.ToString("F4"), FB.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); if (bIsFactorial) { cols = new string[] { "interacts ", tbDF.ToString("F0"), SSFL.ToString("F4"), MSFL.ToString("F4"), FTB.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); } cols = new string[] { "error ", ieDF.ToString("F0"), SSE.ToString("F4"), MSE.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { "total ", (y.Count() - 1).ToString("F0"), (SSTotal).ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); cols = new string[] { string.Concat("F Crit ", sTreats), FCriticalTValue.ToString("F5"), "F > F Critical", FTGreaterFCritical }; sb.AppendLine(Shared.GetLine(cols, true)); cols = new string[] { string.Concat("F Crit ", sBlocks), FCriticalBValue.ToString("F5"), "F > F Critical", FBGreaterFCritical }; sb.AppendLine(Shared.GetLine(cols, true)); if (bIsFactorial) { cols = new string[] { "F Crit Interacts", FCriticalTBValue.ToString("F5"), "F > F Critical", FTBGreaterFCritical }; sb.AppendLine(Shared.GetLine(cols, true)); } } cols = new string[] { "estimate", "mean diff", string.Concat("lower ", _confidenceInt.ToString(), "%"), string.Concat("upper ", _confidenceInt.ToString(), "%") }; sb.AppendLine(Shared.GetLine(cols, true)); //same report for calculator and analyzer for (int i = 0; i < _totalsNeeded; i++) { if (totals[i].Count >= 5) { if (i == 0) { QTPredicted = totals[i].ElementAt(0); QTL = QTPredicted - totals[i].ElementAt(4); QTU = QTPredicted + totals[i].ElementAt(4); cols = new string[] { "Treat 1 Mean ", QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); } else { QTPredicted = totals[i].ElementAt(1); QTL = QTPredicted - totals[i].ElementAt(2); QTU = QTPredicted + totals[i].ElementAt(2); cols = new string[] { string.Concat("xminus1 ", i.ToString(), " "), QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); QTPredicted = totals[i].ElementAt(3); QTL = QTPredicted - totals[i].ElementAt(4); QTU = QTPredicted + totals[i].ElementAt(4); cols = new string[] { string.Concat("base ", i.ToString(), " "), QTPredicted.ToString("F4"), QTL.ToString("F4"), QTU.ToString("F4") }; sb.AppendLine(Shared.GetLine(cols, false)); } } } if (this.MathResult.ToLower().StartsWith("http")) { bool bHasSaved = await CalculatorHelpers.SaveTextInURI( _params.ExtensionDocToCalcURI, sb.ToString(), this.MathResult); if (!string.IsNullOrEmpty(_params.ExtensionDocToCalcURI.ErrorMessage)) { this.MathResult += _params.ExtensionDocToCalcURI.ErrorMessage; //done with errormsg _params.ExtensionDocToCalcURI.ErrorMessage = string.Empty; } } else { this.MathResult = sb.ToString(); } bHasCalculations = true; } catch (Exception ex) { this.ErrorMessage = ex.Message; } return(bHasCalculations); }