示例#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());
        }
示例#2
0
        // Run the simulation of the population system S for N timesteps of length dt.
        // The population at each timestep is stored in the rows of Data.
        static void SimulateNative(int N, double dt, double[,] Data, PopulationSystem S)
        {
            // Loop over the sample range requested.
            for (int n = 1; n < N; ++n)
            {
                // Loop over the species and compute the population change.
                for (int i = 0; i < S.N; ++i)
                {
                    double dx_dt = 1.0;
                    for (int j = 0; j < S.N; ++j)
                    {
                        dx_dt -= S.A[i, j] * Data[n - 1, j];
                    }
                    dx_dt *= S.r[i] * Data[n - 1, i];

                    Data[n, i] = Data[n - 1, i] + dt * dx_dt;
                }
            }
        }
示例#3
0
        static void Main(string[] args)
        {
            // The number of timesteps simulated.
            const int N = 100000;
            // Time between timesteps.
            const double dt = 0.001;

            // First, we define an example population system description:
            PopulationSystem S = new PopulationSystem(4);

            S.x[0] = 0.2;
            S.x[1] = 0.4586;
            S.x[2] = 0.1307;
            S.x[3] = 0.3557;

            S.r[0] = 1;
            S.r[1] = 0.72;
            S.r[2] = 1.53;
            S.r[3] = 1.27;

            S.A[0, 0] = 1;      S.A[0, 1] = 1.09;   S.A[0, 2] = 1.52;   S.A[0, 3] = 0;
            S.A[1, 0] = 0;      S.A[1, 1] = 1;      S.A[1, 2] = 0.44;   S.A[1, 3] = 1.36;
            S.A[2, 0] = 2.33;   S.A[2, 1] = 0;      S.A[2, 2] = 1;      S.A[2, 3] = 0.47;
            S.A[3, 0] = 1.21;   S.A[3, 1] = 0.51;   S.A[3, 2] = 0.35;   S.A[3, 3] = 1;

            // Define a function to run the simulation specifically for S.
            Func <int, double[, ], int> SimulateAlgebra = DefineSimulate(dt, S);

            double native    = RunSimulation((_N, _dt, _Data) => SimulateNative(_N, _dt, _Data, S), N, dt, S, "Native Simulation");
            double hardcoded = RunSimulation((_N, _dt, _Data) => SimulateNativeHardCoded(_N, _Data), N, dt, S, "Native Simulation (hard-coded)");
            double algebra   = RunSimulation((_N, _dt, _Data) => SimulateAlgebra(_N, _Data), N, dt, S, "Algebraic Simulation");

            Console.WriteLine("Algebraic simulation is {0:G3}x faster than native simulation, {1:G3}x faster than hardcoded simulation", native / algebra, hardcoded / algebra);

            // On my machine, the above indicates that the algebraic simulation is 14x faster than native, and ~1.5x faster than the hardcoded simulation.
        }
示例#4
0
        static double RunSimulation(Action <int, double, double[, ]> Simulate, int N, double dt, PopulationSystem S, string Title)
        {
            // Array of doubles representing the populations over time.
            double[,] data = new double[N, S.N];
            // Initialize the system to have the population specified in the system.
            for (int i = 0; i < S.N; ++i)
            {
                data[0, i] = S.x[i];
            }

            // Run the simulation once first to ensure JIT has ocurred if necessary.
            Simulate(N, dt, data);

            // Start time of the simulation.
            long start = Timer.Counter;

            // run the simulation 100 times to avoid noise.
            for (int i = 0; i < 100; ++i)
            {
                Simulate(N, dt, data);
            }
            double time = Timer.Delta(start);

            Console.WriteLine("{0} time: {1}", Title, time);

            // Plot the resulting data.
            Plot plot = new Plot()
            {
                x0     = 0.0,
                x1     = N,
                Title  = Title,
                xLabel = "Timestep",
                yLabel = "Population",
            };

            for (int i = 0; i < S.N; ++i)
            {
                KeyValuePair <double, double>[] points = new KeyValuePair <double, double> [N];
                for (int j = 0; j < N; ++j)
                {
                    points[j] = new KeyValuePair <double, double>(j, data[j, i]);
                }
                plot.Series.Add(new Scatter(points)
                {
                    Name = i.ToString()
                });
            }

            return(time);
        }
示例#5
0
        // Run the simulation of the population system S for N timesteps of length dt.
        // The population at each timestep is stored in the rows of Data.
        static void SimulateNative(int N, double dt, double[,] Data, PopulationSystem S)
        {
            // Loop over the sample range requested.
            for (int n = 1; n < N; ++n)
            {
                // Loop over the species and compute the population change.
                for (int i = 0; i < S.N; ++i)
                {
                    double dx_dt = 1.0;
                    for (int j = 0; j < S.N; ++j)
                        dx_dt -= S.A[i, j] * Data[n - 1, j];
                    dx_dt *= S.r[i] * Data[n - 1, i];

                    Data[n, i] = Data[n - 1, i] + dt * dx_dt;
                }
            }
        }
示例#6
0
        static double RunSimulation(Action<int, double, double[,]> Simulate, int N, double dt, PopulationSystem S, string Title)
        {
            // Array of doubles representing the populations over time.
            double[,] data = new double[N, S.N];
            // Initialize the system to have the population specified in the system.
            for (int i = 0; i < S.N; ++i)
                data[0, i] = S.x[i];

            // Run the simulation once first to ensure JIT has ocurred if necessary.
            Simulate(N, dt, data);

            // Start time of the simulation.
            long start = Timer.Counter;
            // run the simulation 100 times to avoid noise.
            for (int i = 0; i < 100; ++i)
                Simulate(N, dt, data);
            double time = Timer.Delta(start);
            Console.WriteLine("{0} time: {1}", Title, time);

            // Plot the resulting data.
            Plot plot = new Plot()
            {
                x0 = 0.0,
                x1 = N,
                Title = Title,
                xLabel = "Timestep",
                yLabel = "Population",
            };
            for (int i = 0; i < S.N; ++i)
            {
                KeyValuePair<double, double>[] points = new KeyValuePair<double, double>[N];
                for (int j = 0; j < N; ++j)
                    points[j] = new KeyValuePair<double, double>(j, data[j, i]);
                plot.Series.Add(new Scatter(points) { Name = i.ToString() });
            }

            return time;
        }
示例#7
0
        static void Main(string[] args)
        {
            // The number of timesteps simulated.
            const int N = 100000;
            // Time between timesteps.
            const double dt = 0.001;

            // First, we define an example population system description:
            PopulationSystem S = new PopulationSystem(4);

            S.x[0] = 0.2;
            S.x[1] = 0.4586;
            S.x[2] = 0.1307;
            S.x[3] = 0.3557;

            S.r[0] = 1;
            S.r[1] = 0.72;
            S.r[2] = 1.53;
            S.r[3] = 1.27;

            S.A[0, 0] = 1;      S.A[0, 1] = 1.09;   S.A[0, 2] = 1.52;   S.A[0, 3] = 0;
            S.A[1, 0] = 0;      S.A[1, 1] = 1;      S.A[1, 2] = 0.44;   S.A[1, 3] = 1.36;
            S.A[2, 0] = 2.33;   S.A[2, 1] = 0;      S.A[2, 2] = 1;      S.A[2, 3] = 0.47;
            S.A[3, 0] = 1.21;   S.A[3, 1] = 0.51;   S.A[3, 2] = 0.35;   S.A[3, 3] = 1;

            // Define a function to run the simulation specifically for S.
            Func<int, double[,], int> SimulateAlgebra = DefineSimulate(dt, S);

            double native = RunSimulation((_N, _dt, _Data) => SimulateNative(_N, _dt, _Data, S), N, dt, S, "Native Simulation");
            double hardcoded = RunSimulation((_N, _dt, _Data) => SimulateNativeHardCoded(_N, _Data), N, dt, S, "Native Simulation (hard-coded)");
            double algebra = RunSimulation((_N, _dt, _Data) => SimulateAlgebra(_N, _Data), N, dt, S, "Algebraic Simulation");

            Console.WriteLine("Algebraic simulation is {0:G3}x faster than native simulation, {1:G3}x faster than hardcoded simulation", native / algebra, hardcoded / algebra);

            // On my machine, the above indicates that the algebraic simulation is 14x faster than native, and ~1.5x faster than the hardcoded simulation.
        }
示例#8
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();
        }