// 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());
}