/// <summary> /// Solve a linear equation or system of linear equations. /// </summary> /// <param name="Equations">Equation or set of equations to solve.</param> /// <param name="For">Variable of set of variables to solve for.</param> /// <returns>The solved values of x, including non-independent solutions.</returns> public static List<Arrow> Solve(this IEnumerable<Equal> Equations, IEnumerable<Expression> For) { SystemOfEquations S = new SystemOfEquations(Equations, For); S.RowReduce(); S.BackSubstitute(); return S.Solve(); }
public void ShouldSolveSystemWith1EquationAnd1Variable() { // x = 2 var variableX = new Variable("x"); var left = new Expression(1, variableX); var right = new Expression(2, Variable.NULL); var equation = new Equation(left, right); var equationList = new List<Equation>(); equationList.Add(equation); var target = new SystemOfEquations(equationList); target.Solve(); var result = variableX.Value; Assert.AreEqual(1, result.Count); Assert.AreEqual(2, result.First().Coefficient); Assert.AreEqual(Variable.NULL, result.First().Variable); }
public void ShouldSolveUnSortedSystemWith3ComplexEquations() { //x=1; y=2; z=3; //x+2y-z = 2 // z = 3 //x-y = -1 var variableX = new Variable("x"); var variableY = new Variable("y"); var variableZ = new Variable("z"); var left1FirstEq = new Expression(1, variableX); var left2FirstEq = new Expression(2, variableY); var left3FirstEq = new Expression(-1, variableZ); var rightFirstEq = new Expression(2, Variable.NULL); var left1SecondEq = new Expression(1, variableZ); var rightSecondEq = new Expression(3, Variable.NULL); var left1ThirdEq = new Expression(1, variableX); var left2ThirdEq = new Expression(-1, variableY); var rightThirdEq = new Expression(-1, Variable.NULL); var firstEquation = new Equation(new List<Expression>() { left1FirstEq, left2FirstEq,left3FirstEq }, rightFirstEq); var secondEquation = new Equation(new List<Expression>() { left1SecondEq }, rightSecondEq); var thirdEquation = new Equation(new List<Expression>() {left1ThirdEq, left2ThirdEq}, rightThirdEq); var target = new SystemOfEquations(new List<Equation>() {firstEquation, secondEquation, thirdEquation}); target.Solve(); var resultX = variableX.Value; var resultY = variableY.Value; var resultZ = variableZ.Value; Assert.AreEqual(1, resultX.Count); Assert.AreEqual(1, resultY.Count); Assert.AreEqual(1, resultZ.Count); Assert.AreEqual(Variable.NULL, resultX.First().Variable); Assert.AreEqual(1, resultX.First().Coefficient); Assert.AreEqual(Variable.NULL, resultY.First().Variable); Assert.AreEqual(2, resultY.First().Coefficient); Assert.AreEqual(Variable.NULL, resultZ.First().Variable); Assert.AreEqual(3, resultZ.First().Coefficient); }
/// <summary> /// Solve the circuit for transient simulation. /// </summary> /// <param name="Analysis">Analysis from the circuit to solve.</param> /// <param name="TimeStep">Discretization timestep.</param> /// <param name="Log">Where to send output.</param> /// <returns>TransientSolution describing the solution of the circuit.</returns> public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IEnumerable <Arrow> InitialConditions, ILog Log) { Expression h = TimeStep; Log.WriteLine(MessageType.Info, "Building solution for h={0}", TimeStep.ToString()); // Analyze the circuit to get the MNA system and unknowns. List <Equal> mna = Analysis.Equations.ToList(); List <Expression> y = Analysis.Unknowns.ToList(); LogExpressions(Log, MessageType.Verbose, "System of " + mna.Count + " equations and " + y.Count + " unknowns = {{ " + String.Join(", ", y) + " }}", mna); // Evaluate for simulation functions. // Define T = step size. Analysis.Add("T", h); // Define d[t] = delta function. Analysis.Add(ExprFunction.New("d", Call.If((0 <= t) & (t < h), 1, 0), t)); // Define u[t] = step function. Analysis.Add(ExprFunction.New("u", Call.If(t >= 0, 1, 0), t)); mna = mna.Resolve(Analysis).OfType <Equal>().ToList(); // Find out what variables have differential relationships. List <Expression> dy_dt = y.Where(i => mna.Any(j => j.DependsOn(D(i, t)))).Select(i => D(i, t)).ToList(); // Find steady state solution for initial conditions. List <Arrow> initial = InitialConditions.ToList(); Log.WriteLine(MessageType.Info, "Performing steady state analysis..."); SystemOfEquations dc = new SystemOfEquations(mna // Derivatives, t, and T are zero in the steady state. .Evaluate(dy_dt.Select(i => Arrow.New(i, 0)).Append(Arrow.New(t, 0), Arrow.New(T, 0))) // Use the initial conditions from analysis. .Evaluate(Analysis.InitialConditions) // Evaluate variables at t=0. .OfType <Equal>(), y.Select(j => j.Evaluate(t, 0))); // Solve partitions independently. foreach (SystemOfEquations i in dc.Partition()) { try { List <Arrow> part = i.Equations.Select(j => Equal.New(j, 0)).NSolve(i.Unknowns.Select(j => Arrow.New(j, 0))); initial.AddRange(part); LogExpressions(Log, MessageType.Verbose, "Initial conditions:", part); } catch (Exception) { Log.WriteLine(MessageType.Warning, "Failed to find partition initial conditions, simulation may be unstable."); } } // Transient analysis of the system. Log.WriteLine(MessageType.Info, "Performing transient analysis..."); SystemOfEquations system = new SystemOfEquations(mna, dy_dt.Concat(y)); // Solve the diff eq for dy/dt and integrate the results. system.RowReduce(dy_dt); system.BackSubstitute(dy_dt); IEnumerable <Equal> integrated = system.Solve(dy_dt) .NDIntegrate(t, h, IntegrationMethod.Trapezoid) // NDIntegrate finds y[t + h] in terms of y[t], we need y[t] in terms of y[t - h]. .Evaluate(t, t - h).Cast <Arrow>() .Select(i => Equal.New(i.Left, i.Right)).Buffer(); system.AddRange(integrated); LogExpressions(Log, MessageType.Verbose, "Integrated solutions:", integrated); LogExpressions(Log, MessageType.Verbose, "Discretized system:", system.Select(i => Equal.New(i, 0))); // Solving the system... List <SolutionSet> solutions = new List <SolutionSet>(); // Partition the system into independent systems of equations. foreach (SystemOfEquations F in system.Partition()) { // Find linear solutions for y. Linear systems should be completely solved here. F.RowReduce(); IEnumerable <Arrow> linear = F.Solve(); if (linear.Any()) { linear = Factor(linear); solutions.Add(new LinearSolutions(linear)); LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linear); } // If there are any variables left, there are some non-linear equations requiring numerical techniques to solve. if (F.Unknowns.Any()) { // The variables of this system are the newton iteration updates. List <Expression> dy = F.Unknowns.Select(i => NewtonIteration.Delta(i)).ToList(); // Compute JxF*dy + F(y0) == 0. SystemOfEquations nonlinear = new SystemOfEquations( F.Select(i => i.Gradient(F.Unknowns).Select(j => new KeyValuePair <Expression, Expression>(NewtonIteration.Delta(j.Key), j.Value)) .Append(new KeyValuePair <Expression, Expression>(1, i))), dy); // ly is the subset of y that can be found linearly. List <Expression> ly = dy.Where(j => !nonlinear.Any(i => i[j].DependsOn(NewtonIteration.DeltaOf(j)))).ToList(); // Find linear solutions for dy. nonlinear.RowReduce(ly); IEnumerable <Arrow> solved = nonlinear.Solve(ly); solved = Factor(solved); // Initial guess for y[t] = y[t - h]. IEnumerable <Arrow> guess = F.Unknowns.Select(i => Arrow.New(i, i.Evaluate(t, t - h))).ToList(); guess = Factor(guess); // Newton system equations. IEnumerable <LinearCombination> equations = nonlinear.Equations; equations = Factor(equations); solutions.Add(new NewtonIteration(solved, equations, nonlinear.Unknowns, guess)); LogExpressions(Log, MessageType.Verbose, String.Format("Non-linear Newton's method updates ({0}):", String.Join(", ", nonlinear.Unknowns)), equations.Select(i => Equal.New(i, 0))); LogExpressions(Log, MessageType.Verbose, "Linear Newton's method updates:", solved); } } Log.WriteLine(MessageType.Info, "System solved, {0} solution sets for {1} unknowns.", solutions.Count, solutions.Sum(i => i.Unknowns.Count())); return(new TransientSolution( h, solutions, initial)); }
public void TestInitialize() { library = new SystemOfEquations(); }
/// <summary> /// Solve the circuit for transient simulation. /// </summary> /// <param name="Analysis">Analysis from the circuit to solve.</param> /// <param name="TimeStep">Discretization timestep.</param> /// <param name="Log">Where to send output.</param> /// <returns>TransientSolution describing the solution of the circuit.</returns> public static TransientSolution Solve(Analysis Analysis, Expression TimeStep, IEnumerable<Arrow> InitialConditions, ILog Log) { Expression h = TimeStep; Log.WriteLine(MessageType.Info, "Building solution for h={0}", TimeStep.ToString()); // Analyze the circuit to get the MNA system and unknowns. List<Equal> mna = Analysis.Equations.ToList(); List<Expression> y = Analysis.Unknowns.ToList(); LogExpressions(Log, MessageType.Verbose, "System of " + mna.Count + " equations and " + y.Count + " unknowns = {{ " + String.Join(", ", y) + " }}", mna); // Evaluate for simulation functions. // Define T = step size. Analysis.Add("T", h); // Define d[t] = delta function. Analysis.Add(ExprFunction.New("d", Call.If((0 <= t) & (t < h), 1, 0), t)); // Define u[t] = step function. Analysis.Add(ExprFunction.New("u", Call.If(t >= 0, 1, 0), t)); mna = mna.Resolve(Analysis).OfType<Equal>().ToList(); // Find out what variables have differential relationships. List<Expression> dy_dt = y.Where(i => mna.Any(j => j.DependsOn(D(i, t)))).Select(i => D(i, t)).ToList(); // Find steady state solution for initial conditions. List<Arrow> initial = InitialConditions.ToList(); Log.WriteLine(MessageType.Info, "Performing steady state analysis..."); SystemOfEquations dc = new SystemOfEquations(mna // Derivatives, t, and T are zero in the steady state. .Evaluate(dy_dt.Select(i => Arrow.New(i, 0)).Append(Arrow.New(t, 0), Arrow.New(T, 0))) // Use the initial conditions from analysis. .Evaluate(Analysis.InitialConditions) // Evaluate variables at t=0. .OfType<Equal>(), y.Select(j => j.Evaluate(t, 0))); // Solve partitions independently. foreach (SystemOfEquations i in dc.Partition()) { try { List<Arrow> part = i.Equations.Select(j => Equal.New(j, 0)).NSolve(i.Unknowns.Select(j => Arrow.New(j, 0))); initial.AddRange(part); LogExpressions(Log, MessageType.Verbose, "Initial conditions:", part); } catch (Exception) { Log.WriteLine(MessageType.Warning, "Failed to find partition initial conditions, simulation may be unstable."); } } // Transient analysis of the system. Log.WriteLine(MessageType.Info, "Performing transient analysis..."); SystemOfEquations system = new SystemOfEquations(mna, dy_dt.Concat(y)); // Solve the diff eq for dy/dt and integrate the results. system.RowReduce(dy_dt); system.BackSubstitute(dy_dt); IEnumerable<Equal> integrated = system.Solve(dy_dt) .NDIntegrate(t, h, IntegrationMethod.Trapezoid) // NDIntegrate finds y[t + h] in terms of y[t], we need y[t] in terms of y[t - h]. .Evaluate(t, t - h).Cast<Arrow>() .Select(i => Equal.New(i.Left, i.Right)).Buffer(); system.AddRange(integrated); LogExpressions(Log, MessageType.Verbose, "Integrated solutions:", integrated); LogExpressions(Log, MessageType.Verbose, "Discretized system:", system.Select(i => Equal.New(i, 0))); // Solving the system... List<SolutionSet> solutions = new List<SolutionSet>(); // Partition the system into independent systems of equations. foreach (SystemOfEquations F in system.Partition()) { // Find linear solutions for y. Linear systems should be completely solved here. F.RowReduce(); IEnumerable<Arrow> linear = F.Solve(); if (linear.Any()) { linear = Factor(linear); solutions.Add(new LinearSolutions(linear)); LogExpressions(Log, MessageType.Verbose, "Linear solutions:", linear); } // If there are any variables left, there are some non-linear equations requiring numerical techniques to solve. if (F.Unknowns.Any()) { // The variables of this system are the newton iteration updates. List<Expression> dy = F.Unknowns.Select(i => NewtonIteration.Delta(i)).ToList(); // Compute JxF*dy + F(y0) == 0. SystemOfEquations nonlinear = new SystemOfEquations( F.Select(i => i.Gradient(F.Unknowns).Select(j => new KeyValuePair<Expression, Expression>(NewtonIteration.Delta(j.Key), j.Value)) .Append(new KeyValuePair<Expression, Expression>(1, i))), dy); // ly is the subset of y that can be found linearly. List<Expression> ly = dy.Where(j => !nonlinear.Any(i => i[j].DependsOn(NewtonIteration.DeltaOf(j)))).ToList(); // Find linear solutions for dy. nonlinear.RowReduce(ly); IEnumerable<Arrow> solved = nonlinear.Solve(ly); solved = Factor(solved); // Initial guess for y[t] = y[t - h]. IEnumerable<Arrow> guess = F.Unknowns.Select(i => Arrow.New(i, i.Evaluate(t, t - h))).ToList(); guess = Factor(guess); // Newton system equations. IEnumerable<LinearCombination> equations = nonlinear.Equations; equations = Factor(equations); solutions.Add(new NewtonIteration(solved, equations, nonlinear.Unknowns, guess)); LogExpressions(Log, MessageType.Verbose, String.Format("Non-linear Newton's method updates ({0}):", String.Join(", ", nonlinear.Unknowns)), equations.Select(i => Equal.New(i, 0))); LogExpressions(Log, MessageType.Verbose, "Linear Newton's method updates:", solved); } } Log.WriteLine(MessageType.Info, "System solved, {0} solution sets for {1} unknowns.", solutions.Count, solutions.Sum(i => i.Unknowns.Count())); return new TransientSolution( h, solutions, initial); }
public void ShouldSolveSystemWith1EquationAnd2Variables() { //x+y=10 x=6; y=4 //x-y=2 var variableX = new Variable("x"); var variableY = new Variable("y"); var left1FirstEq = new Expression(1, variableX); var left2FirstEq = new Expression(1, variableY); var rightFirstEq = new Expression(10, Variable.NULL); var left1SecondEq = new Expression(1, variableX); var left2SecondEq = new Expression(-1, variableY); var rightSecondEq = new Expression(2, Variable.NULL); var firstEquation = new Equation(new List<Expression>() { left1FirstEq, left2FirstEq }, rightFirstEq); var secondEquation = new Equation(new List<Expression>() {left1SecondEq, left2SecondEq}, rightSecondEq); var target = new SystemOfEquations(new List<Equation>() {firstEquation, secondEquation}); target.Solve(); var resultX = variableX.Value; var resultY = variableY.Value; Assert.AreEqual(1, resultX.Count); Assert.AreEqual(1, resultY.Count); Assert.AreEqual(Variable.NULL, resultX.First().Variable); Assert.AreEqual(6, resultX.First().Coefficient); Assert.AreEqual(Variable.NULL, resultY.First().Variable); Assert.AreEqual(4, resultY.First().Coefficient); }