Решение некоторых проблем требует задания многоразмерных данных. Как и большинство других инструментов системной динамики, AnyLogic поддерживает переменные-массивы.
Массив представляет собой хранилище чисел - своего рода матрицу, у которой может быть произвольное количество размерностей. Каждая размерность имеет конечное число элементов - индексов. Только AnyLogic не имеет ограничений на количество размерностей в массиве, позволяя создавать массивы с любым количеством размерностей.
Массивы используются, когда:
Поскольку второй случай используется намного чаще, рассмотрим его более подробно. Пусть есть несколько подсистем, имеющих одинаковую структуру, но разные характеристики, заданные с помощью численных параметров. Предположим, вы создаете модель здоровья нации, в которой люди условно разделяются по трем характеристикам: полу, возрасту, и общественному положению. Вы можете создать такую многоуровневую модель, создав несколько отдельных моделей, по модели на каждую определенную группу населения. У этого подхода есть огромный недостаток: при необходимости изменения чего-либо в логике моделируемой системы, вам нужно будет внести эти изменения в каждую такую модель.
С помощью же массивов вы можете создать такую многоуровневую модель на одной диаграмме. Рассмотренные характеристики удобно описываются с помощью перечислений: вместо того, чтобы создавать несколько различных моделей (по модели на каждую определенную группу населения), вы можете просто создать массив со следующими размерностями: Gender(male, female), Age(child, teenager, adult, aged) и SocialGroup(wealthy, middleclass, deprived). Такая модель будет более компактной, и производимые вами изменения будут касаться не одного уровня, а всей многоуровневой модели.
Массивами в AnyLogic могут быть объявлены накопители, потоки, динамические переменные, а также параметры.
Демо модель: Bass Diffusion Arrays
Переменные типа массив в графическом редакторе
Некоторые переменные системной динамики типа массив (накопители, параметры а также объявленные константами потоки и динамические переменные) должны быть проинициализированы (то есть, должны быть заданы начальные значения элементов этих массивов).
AnyLogic предоставляет пользователям простой и удобный редактор начальных значений массива. Это сделано потому, что процесс инициализации многомерных массивов является нетривиальной задачей, прежде всего потому, что не существует простого и наглядного способа представления на плоскости многомерных данных.
Поскольку массивы могут иметь неограниченное количество размерностей, каждая из которых может иметь множество элементов, то единственным удобным способом задания значений элементов массива является разбиение этого массива на срезы и инициализация каждого такого среза в отдельности.
Срез задается следующим образом - вы фиксируете значения во всех размерностях массива, кроме двух. Под фиксацией значения понимается выбор из размерности одного конкретного элемента. Тем самым, каждой такой фиксацией вы сужаете список размерностей массива на одну размерность. Сузив этот список до двух размерностей, вы получаете возможность представления данных этого двумерного среза в виде привычной таблицы. Чтобы задать начальные значения для всех элементов массива, нужно перебрать все комбинации элементов фиксируемых вами размерностей.
Чтобы открыть
редактор начальных значений массива
Давайте продемонстрируем на простейших примерах, как нужно задавать начальные значения массивов с помощью этого редактора.
Чтобы
проинициализировать все элементы массива одним значением
Предположим, вы создаете модель, изучающую динамику изменения численности населения в Москве и Санкт-Петербурге. Пусть люди в нашей модели условно разделяются по трем характеристикам: полу, возрасту и месту проживания. Эти характеристики удобно описываются с помощью перечислений: Пол(мужчина, женщина), Возраст(ребенок, подросток, взрослый, пожилой) и Регион(СПб, Москва).
Давайте рассмотрим, как можно проинициализировать массив с тремя размерностями Население[Регион, Возраст, Пол]:
Чтобы
проинициализировать элементы массива различными значениями
Вы можете проверить, правильно ли вы задали начальные значения с помощью инспектирования значения переменной во время выполнения модели:
В поле Начальное значение (или Значение по умолчанию, если это параметр-массив) будет отображаться текстовое представление инициализации массива. Если вы хотите проинициализировать другой массив похожими значениями, вы можете скопировать эту строку в аналогичное поле этого массива и произвести незначительные изменения значений отдельных элементов массива уже с помощью редактора начальных значений.
Есть несколько способов задания уравнения (или уравнений), определяющих значения элементов переменных-массивов (будь то накопитель, поток или динамическая переменная).
В простейшем случае для всех элементов массива
задается одно и то же уравнение, возможно, ссылающееся на размерности массива.
Например, если
накопитель Population
является массивом
с размерностями:
Region = {NORTH, SOUTH} и Gender = { MALE, FEMALE } то уравнение может выглядеть так:
d(Population[Gender,
Region])/dt = Births[Gender, Region]-Deaths[Gender, Region]
Чтобы задать одно
и то же уравнение для всех элементов массива
Это уравнение внутри AnyLogic будет приведено к следующему простейшему
циклу:
for( r : Region )
for( g : Gender )
Population[ r, g ] = Births[ r ] – Deaths[ r, g ]
Если интенсивность рождения Births
одинакова и во всех регионах, то вы можете использовать в этом
уравнении просто скалярную переменную$3Births:
Однако,
в некоторых случаях значения различных элементов массива могут
вычисляться по разным формулам. Предположим, что в рассматриваемой нами
модели населения люди интенсивнее мигрируют из северного региона (NORTH), в то время как
миграция из южного
региона (SOUTH)
незначительна. В этом
случае нужно задать два уравнения для различных элементов накопителя Population:
d(Population[Gender,
SOUTH])/dt =$3Births[SOUTH] - Deaths[Gender,
SOUTH]
d(Population[Gender,
NORTH])/dt =$3Births[NORTH] - Deaths[Gender, NORTH] – OutMigration
$3Чтобы задать
различные уравнения для различных подмассивов
AnyLogic предоставляет вам набор различных функций, в помощью которых вы можете выполнять различные операции над массивами элементов.
С помощью функций, перечисленных в приведенной ниже таблице, вы можете вычислять статистические характеристики массива.
Функция |
Описание |
double average() |
Среднее элементов: |
boolean hasNegativeValues() |
Проверяет, есть ли в массиве элементы с отрицательным значением. Возвращает true, если был найден хотя бы один такой элемент, иначе возвращает false. |
double max() |
Максимальное значение. |
double min() |
Минимальное значение. |
double prod() |
Произведение элементов: |
int size() |
Возвращает общее количество элементов в массиве. |
double stddev() |
Среднеквадратичное отклонение: |
double sum() |
Сумма элементов: |
Вы
можете получать статистические данные по определенным подмассивам
массива. В этом случае, вам нужно перечислить с помощью аргументов
соответствующей функции размерности, образующие этот подмассив.
Например, пусть у вас есть массив people
с размерностями ( Region, Gender,
AgeGroup ),
тогда вызов функции
произведет подсчет количества взрослых людей обоих полов, живущих в северном регионе.
Следующие функции позволяют изменять значения элементов определенного индекса в массиве.
int INDEX_CAN_VARY является константой, которая помещается на место индекса, и позволяет функциям, которые производят операции над размерностями массива, менять значение соответственного индекса. Другие индексы задаются как обычно.
Константа INDEX_CAN_VARY может использоваться, чтобы увеличивать или уменьшать, а также умножать, используя все элементы какой-либо заданной размерности.
Параметры:
indexes - индексы
массива, константа INDEX_CAN_VARY
для изменяющихся индексов
value - значение,
которое нужно добавить
или вычесть для значения элементов массива
factor - фактор,
который применяется к
массиву
Функция |
Описание |
void increment(int... indexes) |
Увеличивает значения элементов ( 1) заданного индекса. |
void incrementBy(double value, int... indexes) |
Увеличивает значения элементов определенного индекса на заданное значение ( value). |
void decrement(int... indexes) |
Уменьшает значения элементов (-1) заданного индекса. |
void decrementBy(double value, int... indexes) |
Уменьшает значения элементов определенного индекса на заданное значение ( -value). |
void multiply(double factor, int... indexes) |
Умножает значения элементов определенного индекса на заданный фактор factor. |