Создается C#-приложение, в котором средствами IMSL Math решается система обыкновенных дифференциальных уравнений (ОДУ). Рассматривается следующая модель Хищник-жертва (модель Лотки-Вольтерра):
dx/dt = a1 * x – b1 * x * y
dy/dt = –a2 * y + b2 * y * x,
в которой
x и y – соответственно плотность популяций хищника и жертвы;
a1 – скорость размножения жертвы в отсутствии хищника;
a2 – естественная смертность хищника;
b1 и b2 – коэффициенты, отвечающие потребности в пище соответственно хищника и жертвы.
Система имеет следующее явное решение:
xa2eb2x = c * ya1e-b1y, c = const.
Для получения результата используется метод Рунге-Кутты.
Решение ОДУ отображается в виде фазового портрета (рис. 1).
Рис. 1. Фазовая диаграмма модели Хищник-жертва
Изменение численности обоих видов происходит по периодическому закону с амплитудой колебаний, определяемой начальными значениями x и y.
В диаграмму вводится маркер в виде залитого красного круга, находящийся в начальной точке расчета (интегрирования).
Начальная точка задает некоторые значения плотностей популяций хищника и жертвы.
В дальнейшем координаты начальной точки определяются положением мыши в момент нажатия ее левой кнопки (событие MouseDown, процедура UpdateInitialPoint).
Всего рассчитываются nPoints точек, по которым выводится фазовый портрет модели.
Данные накапливаются в массивах rabbits и foxes.
Так же начальную точку можно менять, перемещая мышь с нажатой левой клавишей (событие MouseMove). Если перемещение на очень быстрое, то можно наблюдать получаемые с разных начальных точек фазовые портреты.
Число полученных фазовых портретов хранит переменная numberSolved, значение которой отображается методом dataSolved.SetTitle().
Тип проекта - Windows Form Application. Форма, создаваемая при начале нового проекта, и весь связанный с ней код удаляются. Взамен используется приводимая в следующем разделе программа.
Форма, наблюдаемая на рис. 1, генерируется этой программой. Детали построения формы см. в приводимом коде и сопутствующем комментарии.
Подключение недостающих ссылок осуществляется обычным способом: Solution Explorer – References – правая кнопка мыши – Add Reference.
Приводимый код основан на примере, имеющемся в проекте IMSLDemo, поставляемом с библиотекой C#-IMSL.
using System;
using System.Drawing;
using System.Windows.Forms;
using Imsl.Chart2D;
using Imsl.Math;
namespace WindowsFormsApplicationIMSL
{
static class Program
{
// Точка входа приложения
[STAThread]
static void Main()
{
Application.Run(new Predator());
}
}
public class Predator : System.Windows.Forms.Form, Imsl.Math.OdeRungeKutta.IFunction
{
private Imsl.Chart2D.PanelChart panelChart1;
private System.ComponentModel.Container components = null;
private Imsl.Chart2D.AxisXY axis;
// Число точек в фазовом портрете
private const int nPoints = 100;
private double[] rabbits, foxes;
// Стартовая точка
private double[] point = new double[] {2, 3};
// Положение маркера; совпадает с начальной точкой
private double[] initialRabbit = new double[] {2};
private double[] initialFox = new double[] {3};
private Data dataSolved;
private Data dataError;
private int numberSolved;
private bool isMouseDown = false;
public Predator()
{
InitializeComponent();
// Обработчики событий MouseDown, MouseUp и MouseMove
panelChart1.MouseDown += new MouseEventHandler(panelChart1_MouseDown);
panelChart1.MouseUp += new MouseEventHandler(panelChart1_MouseUp);
panelChart1.MouseMove += new MouseEventHandler(panelChart1_MouseMove);
rabbits = new double[nPoints]; // Плотность популяции кроликов
foxes = new double[nPoints]; // Плотность популяции лисиц
SetChart();
try
{
Solve();
}
catch (Exception exception)
{
Console.Out.WriteLine(exception.Message);
return;
}
}
private void InitializeComponent() {
this.panelChart1 = new Imsl.Chart2D.PanelChart();
this.SuspendLayout();
//
// panelChart1
this.panelChart1.Location = new System.Drawing.Point(0, 0);
this.panelChart1.Name = "panelChart1";
this.panelChart1.Size = new System.Drawing.Size(592, 568);
this.panelChart1.TabIndex = 0;
//
// Хищник
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(592, 566);
this.Controls.Add(this.panelChart1);
this.Location = new System.Drawing.Point(64, 64);
this.Name = "Predator";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Хищник-жертва";
this.ResumeLayout(false);
}
private void SetChart()
{
Imsl.Chart2D.Chart chart = panelChart1.Chart;
chart.ChartTitle.FontSize = 12;
chart.ChartTitle.SetTitle("Хищник-жертва");
axis = new AxisXY(chart);
axis.AutoscaleInput = AxisXY.AUTOSCALE_OFF;
axis.AxisX.SetWindow(0.0, 5.0);
axis.AxisY.SetWindow(0.0, 5.0);
axis.AxisX.FontSize = 11;
axis.AxisY.FontSize = 11;
axis.AxisX.AxisTitle.SetTitle("Плотность популяции, Кролики");
axis.AxisY.AxisTitle.SetTitle("Плотность популяции, Лисы");
Data data = new Data(axis, rabbits, foxes);
data.DataType = Data.DATA_TYPE_LINE | Data.DATA_TYPE_MARKER;
// Маркер в позиции мыши; маркер - это залитый круг красного цвета
data.MarkerType = Data.MARKER_TYPE_FILLED_SQUARE;
data.MarkerSize = 0.75;
data.MarkerColor = Color.Blue;
data.LineColor = Color.Blue;
// Показываем маркер в позиции (initialRabbit, initialFox)
data = new Data(axis, initialRabbit, initialFox);
data.DataType = Data.DATA_TYPE_MARKER;
data.MarkerType = Data.MARKER_TYPE_FILLED_CIRCLE;
data.MarkerSize = 1.5;
data.MarkerColor = Color.Red;
// Позиция заголовка, отображающего значение переменной numberSolved
double[] px = {2.5};
double[] py = {4.7};
dataSolved = new Data(axis, px, py);
dataSolved.LabelType = Data.LABEL_TYPE_TITLE;
dataSolved.SetTitle("Решено ОДУ: 1");
dataSolved.TextColor = Color.DarkGreen;
dataSolved.FontSize = 12;
// Позиция сообщения об ошибке
double[] ex = {2.5};
double[] ey = {4.0};
dataError = new Data(axis, ex, ey);
dataError.LabelType = Data.LABEL_TYPE_TITLE;
dataError.SetTitle("");
dataError.TextColor = Color.Red;
dataSolved.FontSize = 12;
}
private void Solve()
{
OdeRungeKutta q = new OdeRungeKutta(this);
double dt = 10.0 / (nPoints - 1);
for (int k = 0; k < nPoints; k++)
{
// Интегрируем ОДУ от k * dt до (k + 1) * dt
q.Solve(k * dt, (k + 1) * dt, point);
// Точка на фазовом портрете в момент времени (k + 1) * dt
rabbits[k] = point[0]; // Плотность популяции кроликов
foxes[k] = point[1]; // Плотность популяции лисиц
}
numberSolved++;
}
private void UpdateInitialPoint(MouseEventArgs e)
{
axis.MapDeviceToUser(e.X, e.Y, point);
initialRabbit[0] = point[0];
initialFox[0] = point[1];
Solve();
dataSolved.SetTitle("Решено ОДУ: " + numberSolved);
dataError.SetTitle("");
Refresh();
}
// Система ОДУ Хищник-жертва
public void F(double t, double[] y, double[] yprime)
{
yprime[0] = 2.0 * y[0] - 2.0 * y[0] * y[1];
yprime[1] = -1.0 * y[1] + 1.0 * y[1] * y[0];
}
private void panelChart1_MouseDown(object sender, MouseEventArgs e)
{
isMouseDown = true;
}
private void panelChart1_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
UpdateInitialPoint(e);
}
private void panelChart1_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown) UpdateInitialPoint(e);
}
}
}