/// <summary> /// solves ax3 + bx2 + cx + d /// </summary> /// <param name="a"> /// Coefficient of x^3 /// </param> /// <param name="b"> /// Coefficient of x^2 /// </param> /// <param name="c"> /// Coefficient of x /// </param> /// <param name="d"> /// Free coefficient /// </param> /// <returns> /// Set of roots /// </returns> internal static Set SolveCubic(Entity a, Entity b, Entity c, Entity d) { // en: https://en.wikipedia.org/wiki/Cubic_equation // ru: https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D0%BC%D1%83%D0%BB%D0%B0_%D0%9A%D0%B0%D1%80%D0%B4%D0%B0%D0%BD%D0%BE // TODO (to remove sympy code!) Set res; if (TreeAnalyzer.IsZero(d)) { res = SolveQuadratic(a, b, c); res.Add(0); return(res); } if (TreeAnalyzer.IsZero(a)) { return(SolveQuadratic(b, c, d)); } res = new Set(); var coeff = MathS.i * MathS.Sqrt(3) / 2; var u1 = new NumberEntity(1); var u2 = SySyn.Rational(-1, 2) + coeff; var u3 = SySyn.Rational(-1, 2) - coeff; var D0 = MathS.Sqr(b) - 3 * a * c; var D1 = (2 * MathS.Pow(b, 3) - 9 * a * b * c + 27 * MathS.Sqr(a) * d).InnerSimplify(); var C = MathS.Pow((D1 + MathS.Sqrt(MathS.Sqr(D1) - 4 * MathS.Pow(D0, 3))) / 2, Number.CreateRational(1, 3)); foreach (var uk in new List <Entity> { u1, u2, u3 }) { Entity r; if (Const.EvalIfCan(C) == 0 && Const.EvalIfCan(D0) == 0) { r = -(b + uk * C) / 3 / a; } else { r = -(b + uk * C + D0 / C / uk) / 3 / a; } res.Add(r); } return(res); }
/// <summary> /// solves ax4 + bx3 + cx2 + dx + e /// </summary> /// <param name="a"> /// Coefficient of x^4 /// </param> /// <param name="b"> /// Coefficient of x^3 /// </param> /// <param name="c"> /// Coefficient of x^2 /// </param> /// <param name="d"> /// Coefficient of x /// </param> /// <param name="e"> /// Free coefficient /// </param> /// <returns> /// Set of roots /// </returns> internal static Set SolveQuartic(Entity a, Entity b, Entity c, Entity d, Entity e) { // en: https://en.wikipedia.org/wiki/Quartic_function // ru: https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%A4%D0%B5%D1%80%D1%80%D0%B0%D1%80%D0%B8 Set res; if (TreeAnalyzer.IsZero(e)) { res = SolveCubic(a, b, c, d); res.Add(0); return(res); } if (TreeAnalyzer.IsZero(a)) { return(SolveCubic(b, c, d, e)); } res = new Set(); var alpha = (-3 * MathS.Sqr(b) / (8 * MathS.Sqr(a)) + c / a) .InnerSimplify(); var beta = (MathS.Pow(b, 3) / (8 * MathS.Pow(a, 3)) - (b * c) / (2 * MathS.Sqr(a)) + d / a) .InnerSimplify(); var gamma = (-3 * MathS.Pow(b, 4) / (256 * MathS.Pow(a, 4)) + MathS.Sqr(b) * c / (16 * MathS.Pow(a, 3)) - (b * d) / (4 * MathS.Sqr(a)) + e / a) .InnerSimplify(); if (Const.EvalIfCan(beta) == 0) { res.FastAddingMode = true; for (int s = -1; s <= 1; s += 2) { for (int t = -1; t <= 1; t += 2) { var x = -b / 4 * a + s * MathS.Sqrt((-alpha + t * MathS.Sqrt(MathS.Sqr(alpha) - 4 * gamma)) / 2); res.Add(x); } } res.FastAddingMode = false; return(res); } var oneThird = Number.CreateRational(1, 3); var P = (-MathS.Sqr(alpha) / 12 - gamma) .InnerSimplify(); var Q = (-MathS.Pow(alpha, 3) / 108 + alpha * gamma / 3 - MathS.Sqr(beta) / 8) .InnerSimplify(); var R = -Q / 2 + MathS.Sqrt(MathS.Sqr(Q) / 4 + MathS.Pow(P, 3) / 27); var U = MathS.Pow(R, oneThird) .InnerSimplify(); var y = (Number.CreateRational(-5, 6) * alpha + U + (Const.EvalIfCan(U) == 0 ? -MathS.Pow(Q, oneThird) : -P / (3 * U))) .InnerSimplify(); var W = MathS.Sqrt(alpha + 2 * y) .InnerSimplify(); // Now we need to permutate all four combinations res.FastAddingMode = true; /* we are sure that there's no such root yet */ for (int s = -1; s <= 1; s += 2) { for (int t = -1; t <= 1; t += 2) { var x = -b / (4 * a) + (s * W + t * MathS.Sqrt(-(3 * alpha + 2 * y + s * 2 * beta / W))) / 2; res.Add(x); } } res.FastAddingMode = false; return(res); }
internal static bool EdgeEqual(Edge A, Edge B) => Const.EvalIfCan(A.Item1) == Const.EvalIfCan(B.Item1) && A.Item2 == B.Item2 && A.Item3 == B.Item3;