static bool RunTest(Expression fx, Func <double, double> Result) { Variable vx = Variable.New("x"); try { Func <double, double> compiled = ExprFunction.New(fx, vx).Compile <Func <double, double> >(); int N = 1000; for (int i = 0; i < N; ++i) { double x = (((double)i / N) * 2 - 1) * Math.PI; if (Math.Abs((double)fx.Evaluate(vx, x) - Result(x)) > 1e-6) { Console.WriteLine("{0} -> {1} != {2}", fx, fx.Evaluate(vx, x), Result(x)); return(false); } if (Math.Abs(compiled(x) - Result(x)) > 1e-6) { Console.WriteLine("Miscompile: {0} -> {1} != {2}", fx, compiled(x), Result(x)); return(false); } } return(true); } catch (Exception Ex) { Console.WriteLine(Ex.Message); return(false); } }
public static void Plot(Expression f, Variable x, Constant x0, Constant x1) { ComputerAlgebra.Plotting.Plot p = new ComputerAlgebra.Plotting.Plot() { x0 = (double)x0, x1 = (double)x1, Title = f.ToString(), xLabel = x.ToString(), }; foreach (Expression i in Set.MembersOf(f)) { p.Series.Add(new ComputerAlgebra.Plotting.Function(ExprFunction.New(i, x)) { Name = i.ToString() }); } }
static void Test(Expression fx, Func <double, double> Result) { Variable vx = Variable.New("x"); Func <double, double> compiled = ExprFunction.New(fx, vx).Compile <Func <double, double> >(); int N = 1000; for (int i = 0; i < N; ++i) { double x = (((double)i / N) * 2 - 1) * Math.PI; if (Math.Abs((double)fx.Evaluate(vx, x) - Result(x)) > 1e-6) { throw new Exception(String.Format("{0} -> {1} != {2}", fx, fx.Evaluate(vx, x), Result(x))); } if (Math.Abs(compiled(x) - Result(x)) > 1e-6) { throw new Exception(String.Format("Miscompile: {0} -> {1} != {2}", fx, compiled(x), Result(x))); } } }
/// <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)); }
/// <summary> /// Compile an expression to a delegate. /// </summary> /// <param name="This"></param> /// <param name="Module"></param> /// <param name="Parameters"></param> /// <returns></returns> public static Delegate Compile(this Expression This, Module Module, IEnumerable <Expression> Parameters) { return(ExprFunction.New( This.Evaluate(Parameters.Select((i, j) => Arrow.New(i, "_" + j.ToString()))), Parameters.Select((i, j) => Variable.New("_" + j.ToString()))).Compile(Module)); }