Функции генерации случайных чисел
На ранних этапах разработки и тестирования модели, удобно подменять фактические данные, - случайно генерированными. Случайно генерируемые данные (далее "случайные данные") могут быть полезны при экспериментах с альтернативными модельными формулировками или решателями. Случайные данные аналогичны вычисляемым параметрам, за исключением того, что их выражения вычисляются с помощью встроенных в AMPL функций генерации случайных чисел. AMPL поддерживает следующие функции генерации случайных чисел:
Beta(a, b) | плотность(x) = xa−1(1−x)b−1/(Γ(a) Γ(b)/Γ(a + b)), x in [0,1] |
Cauchy() | плотность(x) = 1/(π( 1 + x2 ) ) |
Exponential() | плотность(x) = e− x, x > 0 |
Gamma(a) | плотность(x) = xa − 1 e− x / Γ(a) , x≥0, a > 0 |
Irand224() | возвращает целое число в диапазоне [0, 2^24) |
Normal(µ, σ) | нормальное распределение со средним µ, отклонения σ |
Normal01() | нормальное распределение со средним 0, отклонения 1 |
Poisson(µ) | вероятность(k) = e− µ µk / k! , k = 0 , 1 , ... |
Uniform(m, n) | равномерное распределение [m, n) |
Uniform01() | равномерное распределение [0, 1) |
Таблица 1: Функции генерации случайных чисел
В качестве примера, рассмотрим случай генерации случайных значений для параметр avail, представляющего доступные часы работы:
param avail_mean > 0; param avail_variance > 0, < avail_mean / 2; param avail = max(Normal(avail_mean, avail_variance), 0);
Добавление некоторой индексации приводит к многоэтапной версии модели:
param avail {STAGE} = max (Normal (avail_mean, avail_variance), 0);
Для каждой стадии STAGE, происходит генерация отдельного случайного значения для avail[s]. Чтобы указать зависящие от стадии случайные распределения, необходимо добавить индексирование к средним и дисперсионным параметрам:
param avail_mean{STAGE} > 0; param avail_variance{s in STAGE} > 0, < avail_mean[s] / 2; param avai{s in STAGE} = max(Normal(avail_mean[s], avail_variance[s]), 0);
Выражение max(..., 0) включено для обработки редкого случая, когда нормальное распределение с положительным средним возвращает отрицательное значение.
В задаче о смешанных перевозках, мы можем определить случайные доли спроса:
param share{DEST} = Uniform(0,100); param tot_sh = sum{j in DEST}share[j]; param tot_dem{PROD} >= 0; param demand{j in DEST, p in PROD} = share[j] * tot_dem[p] / tot_sh;
Параметры tot_sh и demand также становятся случайными, поскольку они определяются в терминах случайных параметров. В многопериодной модели производства мы можем определить объем спроса market[p,t] в терминах начального значения и случайной суммы увеличения за период:
param market1{PROD} >= 0; param max_incr{PROD} >= 0; param market{p in PROD, t in 1..T+1} = if t = 1 then market1[p] else Uniform(0,max_incr) * market[p,t-1];
или:
param avail{t in 1..T} = if t=1 then 24 else Uniform(0,8) div 1+ avail[t-1];
Такое рекурсивное определение обеспечивает способ генерации простых случайных процессов во времени.
В качестве примера можно рассмотреть следующий код:
param cr{r2 in R1} = if r2 <= 100 then Uniform(10,20) else Uniform(100,200);
Особенности генерации случайных чисел
Все случайные функции AMPL основаны на равномерном генераторе случайных чисел с очень длинным периодом. Когда запускается AMPL или выполняется команда reset, генератор сбрасывается, и повторный вызов функций генерации случайных параметров воспроизводит те же результаты, что и ранее. Если требуются новые значения величин при каждой новой генерации случайных данных, тогда нам необходимо изменить параметр AMPL randseed со значения 1 (по умолчанию) на значение 0:
option randseed n;
где, n - некоторое целочисленное значение. Ненулевые значения дают последовательности, которые повторяются каждый раз при сбросе AMPL. Значение 0 предписывает AMPL производить выбор начального числа на основе текущего значения системных часов, что приводит к генерации различных начальных значений при каждом сбросе.
Применение команды reset data (сброс данных) к случайно вычисленному параметру, также вызывает определение новой выборки случайных значений.
Создание набора на основании случайной выборки элементов из других наборов
Следующий пример показывает как можно создать новый набор D на основании случайного выбора из 3-х имеющихся наборов A={1,3,4,5}, B={7,8,9,10 и C={11,12,13,14}
. В частности, необходимо что бы набор D содержал 2 элемента, случайно выбранных из A, и по 1 элементу из B и C. Например, новый список D может содержать {5,3,9,14}.
Если определить set A ordered, тогда случайный элемент из набора задается выражением:
member(floor(Uniform(1,card(A)+1)),A);
Получить два разных случайных элемента из одного и того же набора немного сложнее, потому что две последовательные случайные выборки могут быть одинаковыми. Следующий сценарий AMPL показывает пример того, как это можно сделать:
set A ordered = {1,3,4,5}; set B ordered = {7,8,9,10}; set NewList default {}; repeat { let NewList := NewList union { member(floor(Uniform(1,card(A)+1)),A) }; } until card(NewList) = 2; let NewList := NewList union{member(floor(Uniform(1,card(B)+1)),B)};
Генерация матрицы значений параметра удовлетворяющих условию
Следующий пример показывает, как для модели можно генерировать матрицу значений параметра, удовлетворяющих условию:
В частности, а должно содержать 0 или 1, нужно сгенерировать а с такими значениями, что бы:
sum{i in Set} a[i,j] == 1 param m; param n; set S = 1..m; set T = 1..n; param a {S,T} default 0; let m := 12; let n := 7; let {j in T} a[ceil(Uniform(0,m)),j] := 1;
Если набор S представляет собой набор строк, а не набор чисел, необходимо сделать его упорядоченным набором, и выражение будет немного сложнее:
set S ordered; set T; param a {S,T} default 0; let S := {"a","b","c","d","e","f","g","h","i","j","k","l"}; let T := {"t","u","v","w","x","y","z"}; let {j in T} a [member (ceil (Uniform (0,card (S) ) ), S), j] := 1;
Чтобы получить более одной единицы в каждом столбце, необходимо объявить команду let {j in T}... необходимое количество раз.