Example #1
0
        // Define a function for running the simulation of a population system S with timestep
        // dt. The number of timesteps and the data buffer are parameters of the defined function.
        static Func <int, double[, ], int> DefineSimulate(double dt, PopulationSystem S)
        {
            CodeGen code = new CodeGen();

            // Define a parameter for the current population x, and define mappings to the
            // expressions defined above.
            LinqExpr N    = code.Decl <int>(Scope.Parameter, "N");
            LinqExpr Data = code.Decl <double[, ]>(Scope.Parameter, "Data");

            // Loop over the sample range requested. Note that this loop is a 'runtime' loop,
            // while the rest of the loops nested in the body of this loop are 'compile time' loops.
            LinqExpr n = code.DeclInit <int>("n", 1);

            code.For(
                () => { },
                LinqExpr.LessThan(n, N),
                () => code.Add(LinqExpr.PostIncrementAssign(n)),
                () =>
            {
                // Define expressions representing the population of each species.
                List <Expression> x = new List <Expression>();
                for (int i = 0; i < S.N; ++i)
                {
                    // Define a variable xi.
                    Expression xi = "x" + i.ToString();
                    x.Add(xi);
                    // xi = Data[n, i].
                    code.DeclInit(xi, LinqExpr.ArrayAccess(Data, LinqExpr.Subtract(n, LinqExpr.Constant(1)), LinqExpr.Constant(i)));
                }

                for (int i = 0; i < S.N; ++i)
                {
                    // This list is the elements of the sum representing the i'th
                    // row of f, i.e. r_i + (A*x)_i.
                    Expression dx_dt = 1;
                    for (int j = 0; j < S.N; ++j)
                    {
                        dx_dt -= S.A[i, j] * x[j];
                    }

                    // Define dx_i/dt = x_i * f_i(x), as per the Lotka-Volterra equations.
                    dx_dt *= x[i] * S.r[i];

                    // Euler's method for x(t) is: x(t) = x(t - h) + h * x'(t - h).
                    Expression integral = x[i] + dt * dx_dt;

                    // Data[n, i] = Data[n - 1, i] + dt * dx_dt;
                    code.Add(LinqExpr.Assign(
                                 LinqExpr.ArrayAccess(Data, n, LinqExpr.Constant(i)),
                                 code.Compile(integral)));
                }
            });

            code.Return(N);

            // Compile the generated code.
            LinqExprs.Expression <Func <int, double[, ], int> > expr = code.Build <Func <int, double[, ], int> >();
            return(expr.Compile());
        }
Example #2
0
        // Solve a system of linear equations
        private static void Solve(CodeGen code, LinqExpr Ab, IEnumerable <LinearCombination> Equations, IEnumerable <Expression> Unknowns)
        {
            LinearCombination[] eqs    = Equations.ToArray();
            Expression[]        deltas = Unknowns.ToArray();

            int M = eqs.Length;
            int N = deltas.Length;

            // Initialize the matrix.
            for (int i = 0; i < M; ++i)
            {
                LinqExpr Abi = code.ReDeclInit <double[]>("Abi", LinqExpr.ArrayAccess(Ab, LinqExpr.Constant(i)));
                for (int x = 0; x < N; ++x)
                {
                    code.Add(LinqExpr.Assign(
                                 LinqExpr.ArrayAccess(Abi, LinqExpr.Constant(x)),
                                 code.Compile(eqs[i][deltas[x]])));
                }
                code.Add(LinqExpr.Assign(
                             LinqExpr.ArrayAccess(Abi, LinqExpr.Constant(N)),
                             code.Compile(eqs[i][1])));
            }

            // Gaussian elimination on this turd.
            //RowReduce(code, Ab, M, N);
            code.Add(LinqExpr.Call(
                         GetMethod <Simulation>("RowReduce", Ab.Type, typeof(int), typeof(int)),
                         Ab,
                         LinqExpr.Constant(M),
                         LinqExpr.Constant(N)));

            // Ab is now upper triangular, solve it.
            for (int j = N - 1; j >= 0; --j)
            {
                LinqExpr _j  = LinqExpr.Constant(j);
                LinqExpr Abj = code.ReDeclInit <double[]>("Abj", LinqExpr.ArrayAccess(Ab, _j));

                LinqExpr r = LinqExpr.ArrayAccess(Abj, LinqExpr.Constant(N));
                for (int ji = j + 1; ji < N; ++ji)
                {
                    r = LinqExpr.Add(r, LinqExpr.Multiply(LinqExpr.ArrayAccess(Abj, LinqExpr.Constant(ji)), code[deltas[ji]]));
                }
                code.DeclInit(deltas[j], LinqExpr.Divide(LinqExpr.Negate(r), LinqExpr.ArrayAccess(Abj, _j)));
            }
        }
Example #3
0
        // Use homotopy method with newton's method to find a solution for F(x) = 0.
        private static List <Arrow> NSolve(List <Expression> F, List <Arrow> x0, double Epsilon, int MaxIterations)
        {
            int M = F.Count;
            int N = x0.Count;

            // Compute JxF, the Jacobian of F.
            List <Dictionary <Expression, Expression> > JxF = Jacobian(F, x0.Select(i => i.Left)).ToList();

            // Define a function to evaluate JxH(x), where H = F(x) - s*F(x0).
            CodeGen code = new CodeGen();

            ParamExpr _JxH = code.Decl <double[, ]>(Scope.Parameter, "JxH");
            ParamExpr _x0  = code.Decl <double[]>(Scope.Parameter, "x0");
            ParamExpr _s   = code.Decl <double>(Scope.Parameter, "s");

            // Load x_j from the input array and add them to the map.
            for (int j = 0; j < N; ++j)
            {
                code.DeclInit(x0[j].Left, LinqExpr.ArrayAccess(_x0, LinqExpr.Constant(j)));
            }

            LinqExpr error = code.Decl <double>("error");

            // Compile the expressions to assign JxH
            for (int i = 0; i < M; ++i)
            {
                LinqExpr _i = LinqExpr.Constant(i);
                for (int j = 0; j < N; ++j)
                {
                    code.Add(LinqExpr.Assign(
                                 LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(j)),
                                 code.Compile(JxF[i][x0[j].Left])));
                }
                // e = F(x) - s*F(x0)
                LinqExpr e = code.DeclInit <double>("e", LinqExpr.Subtract(code.Compile(F[i]), LinqExpr.Multiply(LinqExpr.Constant((double)F[i].Evaluate(x0)), _s)));
                code.Add(LinqExpr.Assign(LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(N)), e));
                // error += e * e
                code.Add(LinqExpr.AddAssign(error, LinqExpr.Multiply(e, e)));
            }

            // return error
            code.Return(error);

            Func <double[, ], double[], double, double> JxH = code.Build <Func <double[, ], double[], double, double> >().Compile();

            double[] x = new double[N];

            // Remember where we last succeeded/failed.
            double s0 = 0.0;
            double s1 = 1.0;

            do
            {
                try
                {
                    // H(F, s) = F - s*F0
                    NewtonsMethod(M, N, JxH, s0, x, Epsilon, MaxIterations);

                    // Success at this s!
                    s1 = s0;
                    for (int i = 0; i < N; ++i)
                    {
                        x0[i] = Arrow.New(x0[i].Left, x[i]);
                    }

                    // Go near the goal.
                    s0 = Lerp(s0, 0.0, 0.9);
                }
                catch (FailedToConvergeException)
                {
                    // Go near the last success.
                    s0 = Lerp(s0, s1, 0.9);

                    for (int i = 0; i < N; ++i)
                    {
                        x[i] = (double)x0[i].Right;
                    }
                }
            } while (s0 > 0.0 && s1 >= s0 + 1e-6);

            // Make sure the last solution is at F itself.
            if (s0 != 0.0)
            {
                NewtonsMethod(M, N, JxH, 0.0, x, Epsilon, MaxIterations);
                for (int i = 0; i < N; ++i)
                {
                    x0[i] = Arrow.New(x0[i].Left, x[i]);
                }
            }

            return(x0);
        }
Example #4
0
        // Generate code to perform row reduction.
        private static void RowReduce(CodeGen code, LinqExpr Ab, int M, int N)
        {
            // For each variable in the system...
            for (int j = 0; j + 1 < N; ++j)
            {
                LinqExpr _j  = LinqExpr.Constant(j);
                LinqExpr Abj = code.ReDeclInit <double[]>("Abj", LinqExpr.ArrayAccess(Ab, _j));
                // int pi = j
                LinqExpr pi = code.ReDeclInit <int>("pi", _j);
                // double max = |Ab[j][j]|
                LinqExpr max = code.ReDeclInit <double>("max", Abs(LinqExpr.ArrayAccess(Abj, _j)));

                // Find a pivot row for this variable.
                //code.For(j + 1, M, _i =>
                //{
                for (int i = j + 1; i < M; ++i)
                {
                    LinqExpr _i = LinqExpr.Constant(i);

                    // if(|Ab[i][j]| > max) { pi = i, max = |Ab[i][j]| }
                    LinqExpr maxj = code.ReDeclInit <double>("maxj", Abs(LinqExpr.ArrayAccess(LinqExpr.ArrayAccess(Ab, _i), _j)));
                    code.Add(LinqExpr.IfThen(
                                 LinqExpr.GreaterThan(maxj, max),
                                 LinqExpr.Block(
                                     LinqExpr.Assign(pi, _i),
                                     LinqExpr.Assign(max, maxj))));
                }

                // (Maybe) swap the pivot row with the current row.
                LinqExpr Abpi = code.ReDecl <double[]>("Abpi");
                code.Add(LinqExpr.IfThen(
                             LinqExpr.NotEqual(_j, pi), LinqExpr.Block(
                                 new[] { LinqExpr.Assign(Abpi, LinqExpr.ArrayAccess(Ab, pi)) }.Concat(
                                     Enumerable.Range(j, N + 1 - j).Select(x => Swap(
                                                                               LinqExpr.ArrayAccess(Abj, LinqExpr.Constant(x)),
                                                                               LinqExpr.ArrayAccess(Abpi, LinqExpr.Constant(x)),
                                                                               code.ReDecl <double>("swap")))))));

                //// It's hard to believe this swap isn't faster than the above...
                //code.Add(LinqExpr.IfThen(LinqExpr.NotEqual(_j, pi), LinqExpr.Block(
                //    Swap(LinqExpr.ArrayAccess(Ab, _j), LinqExpr.ArrayAccess(Ab, pi), Redeclare<double[]>(code, "temp")),
                //    LinqExpr.Assign(Abj, LinqExpr.ArrayAccess(Ab, _j)))));

                // Eliminate the rows after the pivot.
                LinqExpr p = code.ReDeclInit <double>("p", LinqExpr.ArrayAccess(Abj, _j));
                //code.For(j + 1, M, _i =>
                //{
                for (int i = j + 1; i < M; ++i)
                {
                    LinqExpr _i  = LinqExpr.Constant(i);
                    LinqExpr Abi = code.ReDeclInit <double[]>("Abi", LinqExpr.ArrayAccess(Ab, _i));

                    // s = Ab[i][j] / p
                    LinqExpr s = code.ReDeclInit <double>("scale", LinqExpr.Divide(LinqExpr.ArrayAccess(Abi, _j), p));
                    // Ab[i] -= Ab[j] * s
                    for (int ji = j + 1; ji < N + 1; ++ji)
                    {
                        code.Add(LinqExpr.SubtractAssign(
                                     LinqExpr.ArrayAccess(Abi, LinqExpr.Constant(ji)),
                                     LinqExpr.Multiply(LinqExpr.ArrayAccess(Abj, LinqExpr.Constant(ji)), s)));
                    }
                }
            }
        }
Example #5
0
        // The resulting lambda processes N samples, using buffers provided for Input and Output:
        //  void Process(int N, double t0, double T, double[] Input0 ..., double[] Output0 ...)
        //  { ... }
        private Delegate DefineProcess()
        {
            // Map expressions to identifiers in the syntax tree.
            List <KeyValuePair <Expression, LinqExpr> > inputs  = new List <KeyValuePair <Expression, LinqExpr> >();
            List <KeyValuePair <Expression, LinqExpr> > outputs = new List <KeyValuePair <Expression, LinqExpr> >();

            // Lambda code generator.
            CodeGen code = new CodeGen();

            // Create parameters for the basic simulation info (N, t, Iterations).
            ParamExpr SampleCount = code.Decl <int>(Scope.Parameter, "SampleCount");
            ParamExpr t           = code.Decl(Scope.Parameter, Simulation.t);

            // Create buffer parameters for each input...
            foreach (Expression i in Input)
            {
                inputs.Add(new KeyValuePair <Expression, LinqExpr>(i, code.Decl <double[]>(Scope.Parameter, i.ToString())));
            }

            // ... and output.
            foreach (Expression i in Output)
            {
                outputs.Add(new KeyValuePair <Expression, LinqExpr>(i, code.Decl <double[]>(Scope.Parameter, i.ToString())));
            }

            // Create globals to store previous values of inputs.
            foreach (Expression i in Input.Distinct())
            {
                AddGlobal(i.Evaluate(t_t0));
            }

            // Define lambda body.

            // int Zero = 0
            LinqExpr Zero = LinqExpr.Constant(0);

            // double h = T / Oversample
            LinqExpr h = LinqExpr.Constant(TimeStep / (double)Oversample);

            // Load the globals to local variables and add them to the map.
            foreach (KeyValuePair <Expression, GlobalExpr <double> > i in globals)
            {
                code.Add(LinqExpr.Assign(code.Decl(i.Key), i.Value));
            }

            foreach (KeyValuePair <Expression, LinqExpr> i in inputs)
            {
                code.Add(LinqExpr.Assign(code.Decl(i.Key), code[i.Key.Evaluate(t_t0)]));
            }

            // Create arrays for linear systems.
            int      M   = Solution.Solutions.OfType <NewtonIteration>().Max(i => i.Equations.Count(), 0);
            int      N   = Solution.Solutions.OfType <NewtonIteration>().Max(i => i.UnknownDeltas.Count(), 0) + 1;
            LinqExpr JxF = code.DeclInit <double[][]>("JxF", LinqExpr.NewArrayBounds(typeof(double[]), LinqExpr.Constant(M)));

            for (int j = 0; j < M; ++j)
            {
                code.Add(LinqExpr.Assign(LinqExpr.ArrayAccess(JxF, LinqExpr.Constant(j)), LinqExpr.NewArrayBounds(typeof(double), LinqExpr.Constant(N))));
            }

            // for (int n = 0; n < SampleCount; ++n)
            ParamExpr n = code.Decl <int>("n");

            code.For(
                () => code.Add(LinqExpr.Assign(n, Zero)),
                LinqExpr.LessThan(n, SampleCount),
                () => code.Add(LinqExpr.PreIncrementAssign(n)),
                () =>
            {
                // Prepare input samples for oversampling interpolation.
                Dictionary <Expression, LinqExpr> dVi = new Dictionary <Expression, LinqExpr>();
                foreach (Expression i in Input.Distinct())
                {
                    LinqExpr Va = code[i];
                    // Sum all inputs with this key.
                    IEnumerable <LinqExpr> Vbs = inputs.Where(j => j.Key.Equals(i)).Select(j => j.Value);
                    LinqExpr Vb = LinqExpr.ArrayAccess(Vbs.First(), n);
                    foreach (LinqExpr j in Vbs.Skip(1))
                    {
                        Vb = LinqExpr.Add(Vb, LinqExpr.ArrayAccess(j, n));
                    }

                    // dVi = (Vb - Va) / Oversample
                    code.Add(LinqExpr.Assign(
                                 Decl <double>(code, dVi, i, "d" + i.ToString().Replace("[t]", "")),
                                 LinqExpr.Multiply(LinqExpr.Subtract(Vb, Va), LinqExpr.Constant(1.0 / (double)Oversample))));
                }

                // Prepare output sample accumulators for low pass filtering.
                Dictionary <Expression, LinqExpr> Vo = new Dictionary <Expression, LinqExpr>();
                foreach (Expression i in Output.Distinct())
                {
                    code.Add(LinqExpr.Assign(
                                 Decl <double>(code, Vo, i, i.ToString().Replace("[t]", "")),
                                 LinqExpr.Constant(0.0)));
                }

                // int ov = Oversample;
                // do { -- ov; } while(ov > 0)
                ParamExpr ov = code.Decl <int>("ov");
                code.Add(LinqExpr.Assign(ov, LinqExpr.Constant(Oversample)));
                code.DoWhile(() =>
                {
                    // t += h
                    code.Add(LinqExpr.AddAssign(t, h));

                    // Interpolate the input samples.
                    foreach (Expression i in Input.Distinct())
                    {
                        code.Add(LinqExpr.AddAssign(code[i], dVi[i]));
                    }

                    // Compile all of the SolutionSets in the solution.
                    foreach (SolutionSet ss in Solution.Solutions)
                    {
                        if (ss is LinearSolutions)
                        {
                            // Linear solutions are easy.
                            LinearSolutions S = (LinearSolutions)ss;
                            foreach (Arrow i in S.Solutions)
                            {
                                code.DeclInit(i.Left, i.Right);
                            }
                        }
                        else if (ss is NewtonIteration)
                        {
                            NewtonIteration S = (NewtonIteration)ss;

                            // Start with the initial guesses from the solution.
                            foreach (Arrow i in S.Guesses)
                            {
                                code.DeclInit(i.Left, i.Right);
                            }

                            // int it = iterations
                            LinqExpr it = code.ReDeclInit <int>("it", Iterations);
                            // do { ... --it } while(it > 0)
                            code.DoWhile((Break) =>
                            {
                                // Solve the un-solved system.
                                Solve(code, JxF, S.Equations, S.UnknownDeltas);

                                // Compile the pre-solved solutions.
                                if (S.KnownDeltas != null)
                                {
                                    foreach (Arrow i in S.KnownDeltas)
                                    {
                                        code.DeclInit(i.Left, i.Right);
                                    }
                                }

                                // bool done = true
                                LinqExpr done = code.ReDeclInit("done", true);
                                foreach (Expression i in S.Unknowns)
                                {
                                    LinqExpr v  = code[i];
                                    LinqExpr dv = code[NewtonIteration.Delta(i)];

                                    // done &= (|dv| < |v|*epsilon)
                                    code.Add(LinqExpr.AndAssign(done, LinqExpr.LessThan(LinqExpr.Multiply(Abs(dv), LinqExpr.Constant(1e4)), LinqExpr.Add(Abs(v), LinqExpr.Constant(1e-6)))));
                                    // v += dv
                                    code.Add(LinqExpr.AddAssign(v, dv));
                                }
                                // if (done) break
                                code.Add(LinqExpr.IfThen(done, Break));

                                // --it;
                                code.Add(LinqExpr.PreDecrementAssign(it));
                            }, LinqExpr.GreaterThan(it, Zero));

                            //// bool failed = false
                            //LinqExpr failed = Decl(code, code, "failed", LinqExpr.Constant(false));
                            //for (int i = 0; i < eqs.Length; ++i)
                            //    // failed |= |JxFi| > epsilon
                            //    code.Add(LinqExpr.OrAssign(failed, LinqExpr.GreaterThan(Abs(eqs[i].ToExpression().Compile(map)), LinqExpr.Constant(1e-3))));

                            //code.Add(LinqExpr.IfThen(failed, ThrowSimulationDiverged(n)));
                        }
                    }

                    // Update the previous timestep variables.
                    foreach (SolutionSet S in Solution.Solutions)
                    {
                        foreach (Expression i in S.Unknowns.Where(i => globals.Keys.Contains(i.Evaluate(t_t0))))
                        {
                            code.Add(LinqExpr.Assign(code[i.Evaluate(t_t0)], code[i]));
                        }
                    }

                    // Vo += i
                    foreach (Expression i in Output.Distinct())
                    {
                        LinqExpr Voi = LinqExpr.Constant(0.0);
                        try
                        {
                            Voi = code.Compile(i);
                        }
                        catch (Exception Ex)
                        {
                            Log.WriteLine(MessageType.Warning, Ex.Message);
                        }
                        code.Add(LinqExpr.AddAssign(Vo[i], Voi));
                    }

                    // Vi_t0 = Vi
                    foreach (Expression i in Input.Distinct())
                    {
                        code.Add(LinqExpr.Assign(code[i.Evaluate(t_t0)], code[i]));
                    }

                    // --ov;
                    code.Add(LinqExpr.PreDecrementAssign(ov));
                }, LinqExpr.GreaterThan(ov, Zero));

                // Output[i][n] = Vo / Oversample
                foreach (KeyValuePair <Expression, LinqExpr> i in outputs)
                {
                    code.Add(LinqExpr.Assign(LinqExpr.ArrayAccess(i.Value, n), LinqExpr.Multiply(Vo[i.Key], LinqExpr.Constant(1.0 / (double)Oversample))));
                }

                // Every 256 samples, check for divergence.
                if (Vo.Any())
                {
                    code.Add(LinqExpr.IfThen(LinqExpr.Equal(LinqExpr.And(n, LinqExpr.Constant(0xFF)), Zero),
                                             LinqExpr.Block(Vo.Select(i => LinqExpr.IfThenElse(IsNotReal(i.Value),
                                                                                               ThrowSimulationDiverged(n),
                                                                                               LinqExpr.Assign(i.Value, RoundDenormToZero(i.Value)))))));
                }
            });

            // Copy the global state variables back to the globals.
            foreach (KeyValuePair <Expression, GlobalExpr <double> > i in globals)
            {
                code.Add(LinqExpr.Assign(i.Value, code[i.Key]));
            }

            LinqExprs.LambdaExpression lambda = code.Build();
            Delegate ret = lambda.Compile();

            return(ret);
        }
Example #6
0
        // Use homotopy method with newton's method to find a solution for F(x) = 0.
        private static List<Arrow> NSolve(List<Expression> F, List<Arrow> x0, double Epsilon, int MaxIterations)
        {
            int M = F.Count;
            int N = x0.Count;

            // Compute JxF, the Jacobian of F.
            List<Dictionary<Expression, Expression>> JxF = Jacobian(F, x0.Select(i => i.Left)).ToList();

            // Define a function to evaluate JxH(x), where H = F(x) - s*F(x0).
            CodeGen code = new CodeGen();

            ParamExpr _JxH = code.Decl<double[,]>(Scope.Parameter, "JxH");
            ParamExpr _x0 = code.Decl<double[]>(Scope.Parameter, "x0");
            ParamExpr _s = code.Decl<double>(Scope.Parameter, "s");

            // Load x_j from the input array and add them to the map.
            for (int j = 0; j < N; ++j)
                code.DeclInit(x0[j].Left, LinqExpr.ArrayAccess(_x0, LinqExpr.Constant(j)));

            LinqExpr error = code.Decl<double>("error");

            // Compile the expressions to assign JxH
            for (int i = 0; i < M; ++i)
            {
                LinqExpr _i = LinqExpr.Constant(i);
                for (int j = 0; j < N; ++j)
                    code.Add(LinqExpr.Assign(
                        LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(j)),
                        code.Compile(JxF[i][x0[j].Left])));
                // e = F(x) - s*F(x0)
                LinqExpr e = code.DeclInit<double>("e", LinqExpr.Subtract(code.Compile(F[i]), LinqExpr.Multiply(LinqExpr.Constant((double)F[i].Evaluate(x0)), _s)));
                code.Add(LinqExpr.Assign(LinqExpr.ArrayAccess(_JxH, _i, LinqExpr.Constant(N)), e));
                // error += e * e
                code.Add(LinqExpr.AddAssign(error, LinqExpr.Multiply(e, e)));
            }

            // return error
            code.Return(error);

            Func<double[,], double[], double, double> JxH = code.Build<Func<double[,], double[], double, double>>().Compile();

            double[] x = new double[N];

            // Remember where we last succeeded/failed.
            double s0 = 0.0;
            double s1 = 1.0;
            do
            {
                try
                {
                    // H(F, s) = F - s*F0
                    NewtonsMethod(M, N, JxH, s0, x, Epsilon, MaxIterations);

                    // Success at this s!
                    s1 = s0;
                    for (int i = 0; i < N; ++i)
                        x0[i] = Arrow.New(x0[i].Left, x[i]);

                    // Go near the goal.
                    s0 = Lerp(s0, 0.0, 0.9);
                }
                catch (FailedToConvergeException)
                {
                    // Go near the last success.
                    s0 = Lerp(s0, s1, 0.9);

                    for (int i = 0; i < N; ++i)
                        x[i] = (double)x0[i].Right;
                }
            } while (s0 > 0.0 && s1 >= s0 + 1e-6);

            // Make sure the last solution is at F itself.
            if (s0 != 0.0)
            {
                NewtonsMethod(M, N, JxH, 0.0, x, Epsilon, MaxIterations);
                for (int i = 0; i < N; ++i)
                    x0[i] = Arrow.New(x0[i].Left, x[i]);
            }

            return x0;
        }
Example #7
0
        // Define a function for running the simulation of a population system S with timestep
        // dt. The number of timesteps and the data buffer are parameters of the defined function.
        static Func<int, double[, ], int> DefineSimulate(double dt, PopulationSystem S)
        {
            CodeGen code = new CodeGen();

            // Define a parameter for the current population x, and define mappings to the
            // expressions defined above.
            LinqExpr N = code.Decl<int>(Scope.Parameter, "N");
            LinqExpr Data = code.Decl<double[,]>(Scope.Parameter, "Data");

            // Loop over the sample range requested. Note that this loop is a 'runtime' loop,
            // while the rest of the loops nested in the body of this loop are 'compile time' loops.
            LinqExpr n = code.DeclInit<int>("n", 1);
            code.For(
                () => { },
                LinqExpr.LessThan(n, N),
                () => code.Add(LinqExpr.PostIncrementAssign(n)),
                () =>
            {
                // Define expressions representing the population of each species.
                List<Expression> x = new List<Expression>();
                for (int i = 0; i < S.N; ++i)
                {
                    // Define a variable xi.
                    Expression xi = "x" + i.ToString();
                    x.Add(xi);
                    // xi = Data[n, i].
                    code.DeclInit(xi, LinqExpr.ArrayAccess(Data, LinqExpr.Subtract(n, LinqExpr.Constant(1)), LinqExpr.Constant(i)));
                }

                for (int i = 0; i < S.N; ++i)
                {
                    // This list is the elements of the sum representing the i'th
                    // row of f, i.e. r_i + (A*x)_i.
                    Expression dx_dt = 1;
                    for (int j = 0; j < S.N; ++j)
                        dx_dt -= S.A[i, j] * x[j];

                    // Define dx_i/dt = x_i * f_i(x), as per the Lotka-Volterra equations.
                    dx_dt *= x[i] * S.r[i];

                    // Euler's method for x(t) is: x(t) = x(t - h) + h * x'(t - h).
                    Expression integral = x[i] + dt * dx_dt;

                    // Data[n, i] = Data[n - 1, i] + dt * dx_dt;
                    code.Add(LinqExpr.Assign(
                        LinqExpr.ArrayAccess(Data, n, LinqExpr.Constant(i)),
                        code.Compile(integral)));
                }
            });

            code.Return(N);

            // Compile the generated code.
            LinqExprs.Expression<Func<int, double[,], int>> expr = code.Build<Func<int, double[,], int>>();
            return expr.Compile();
        }