public static void TestSymbolism() { // Create some constants. ComputerAlgebra.Expression A = 2; ComputerAlgebra.Constant B = ComputerAlgebra.Constant.New(3); // Create some variables. ComputerAlgebra.Expression x = "x"; Variable y = Variable.New("y"); // Create basic expression with operator overloads. ComputerAlgebra.Expression f = A * x + B * y + 4; // This expression uses the implicit conversion from string to // Expression, which parses the string. ComputerAlgebra.Expression g = "5*x + C*y + 8"; // Create a system of equations from the above expressions. var system = new List <Equal>() { Equal.New(f, 0), Equal.New(g, 0), }; // We can now solve the system of equations for x and y. Since the // equations have a variable 'C', the solutions will not be // constants. List <Arrow> solutions = system.Solve(x, y); Debug.WriteLine("The solutions are:"); foreach (Arrow i in solutions) { Debug.WriteLine(i.ToString()); } }
static void Main(string[] args) { // Create some constants. Expression A = 2; Constant B = Constant.New(3); // Create some variables. Expression x = "x"; Variable y = Variable.New("y"); // Create a basic expressions. Expression f = A * x + B * y + 4; // This expression uses the implicit conversion from string to // Expression, which parses the string. Expression g = "5*x + C*y + 8"; // Create a system of equations from the above expressions. var system = new List <Equal>() { Equal.New(f, 0), Equal.New(g, 0), }; // We can now solve the system of equations for x and y. Since the // equations have a variable 'C', the solutions will not be // constants. List <Arrow> solutions = system.Solve(x, y); Console.WriteLine("The solutions are:"); foreach (Arrow i in solutions) { Console.WriteLine(i.ToString()); } // A fundamental building block of ComputerAlgebra is the 'Arrow' // expression. Arrow expressions define the value of one expression // to be the value given by another expression. For example, 'x->2' // defines the expression 'x' to have the value '2'. // The 'Solve' function used above returns a list of Arrow // expressions defining the solutions of the system. // Arrow expressions are used by the 'Evaluate' function to // substitute values for expressions into other expressions. To // demonstrate the usage of Evaluate, let's validate the solution // by using Evaluate to substitute the solutions into the original // system of equations, and then substitute a value for C. Expression f_xy = f.Evaluate(solutions).Evaluate(Arrow.New("C", 2)); Expression g_xy = g.Evaluate(solutions).Evaluate(Arrow.New("C", 2)); if ((f_xy == 0) && (g_xy == 0)) { Console.WriteLine("Success!"); } else { Console.WriteLine("Failure! f = {0}, g = {1}", f_xy, g_xy); } // Suppose we need to evaluate the solutions efficiently many times. // We can compile the solutions to delegates where 'C' is a // parameter to the delegate, allowing it to be specified later. var x_C = x.Evaluate(solutions).Compile <Func <double, double> >("C"); var y_C = y.Evaluate(solutions).Compile <Func <double, double> >("C"); for (int i = 0; i < 20; ++i) { double C = i / 2.0; Console.WriteLine("C = {0}: (x, y) = ({1}, {2})", C, x_C(C), y_C(C)); } }
/// <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 AddEquation(Expression a, Expression b) { AddEquations(Equal.New(a, b)); }