// Expand N(x)/D(x) using partial fractions. private static Expression ExpandPartialFractions(Expression N, Expression D, Expression x) { List <Expression> terms = new List <Expression>(); List <Variable> unknowns = new List <Variable>(); List <Expression> basis = new List <Expression>(); foreach (Expression i in Product.TermsOf(D)) { // Get the multiplicity of this basis term. Expression e = i; int n = Power.IntegralExponentOf(e); if (n != 1) { e = ((Power)i).Left; } // Convert to a polynomial. Polynomial Pi = Polynomial.New(e, x); // Add new terms for each multiplicity n. for (int j = 1; j <= n; ++j) { // Expression for the unknown numerator of this term. Expression unknown = 0; for (int k = 0; k < Pi.Degree; ++k) { Variable Ai = Variable.New("_A" + unknowns.Count.ToString()); unknown += Ai * (x ^ k); unknowns.Add(Ai); } terms.Add(Product.New(unknown, Power.New(e, -j))); } basis.Add(i); } // Equate the original expression with the decomposed expressions. D = Sum.New(terms.Select(j => (Expression)(D * j))).Expand(); Polynomial l = Polynomial.New(N, x); Polynomial r = Polynomial.New(D, x); // Equate terms of equal degree and solve for the unknowns. int degree = Math.Max(l.Degree, r.Degree); List <Equal> eqs = new List <Equal>(degree + 1); for (int i = 0; i <= degree; ++i) { eqs.Add(Equal.New(l[i], r[i])); } List <Arrow> A = eqs.Solve(unknowns); // Substitute the now knowns. return(Sum.New(terms.Select(i => i.Evaluate(A)))); }
/// <summary> /// Partially solve a linear system of differential equations for y[t] in terms of y[t - h]. See SolveExtensions.PartialSolve for more information. /// </summary> /// <param name="f">Equations to solve.</param> /// <param name="y">Functions to solve for.</param> /// <param name="t">Independent variable.</param> /// <param name="h">Step size.</param> /// <param name="method">Integration method to use for differential equations.</param> /// <returns>Expressions for y[t].</returns> public static List <Arrow> NDPartialSolve(this IEnumerable <Equal> f, IEnumerable <Expression> y, Expression t, Expression h, IntegrationMethod method) { // Find y' in terms of y. List <Arrow> dy_dt = f.Solve(y.Select(i => D(i, t))); // If dy/dt appears on the right side of the system, the differential equation is not linear. Can't handle these. if (dy_dt.Any(i => i.Right.DependsOn(dy_dt.Select(j => j.Left)))) { throw new ArgumentException("Differential equation is singular or not linear."); } return(NDIntegrate(dy_dt, t, h, method) .Select(i => Equal.New(i.Left, i.Right)) .PartialSolve(y)); }
/// <summary> /// Solve a linear system of differential equations with initial conditions using the laplace transform. /// </summary> /// <param name="f"></param> /// <param name="y"></param> /// <param name="y0"></param> /// <param name="t"></param> /// <returns></returns> public static List <Arrow> DSolve(this IEnumerable <Equal> f, IEnumerable <Expression> y, IEnumerable <Arrow> y0, Expression t) { // Find F(s) = L[f(t)] and substitute the initial conditions. List <Equal> F = f.Select(i => Equal.New( L(i.Left, t).Evaluate(y0), L(i.Right, t).Evaluate(y0))).ToList(); // Solve F for Y(s) = L[y(t)]. List <Arrow> Y = F.Solve(y.Select(i => L(i, t))); // Take L^-1[Y]. Y = Y.Select(i => Arrow.New(IL(i.Left, t), IL(i.Right, t))).ToList(); if (Y.DependsOn(s)) { throw new Exception("Could not find L^-1[Y(s)]."); } return(Y); }