\chapter{Структурированные типы данных}
\label{chap:structypes}

В Hansl есть два типа «структурированного типа данных»: ассоциативные
массивы, называемые пакетами, и массивы в буквальном смысле слова
(\emph{bundles and arrays}). Грубо говоря, основное различие между
ними состоит в том, что в связке вы можете собрать вместе переменные
разных типов, в то время как массивы могут содержать лишь один тип
переменной.

\section{Пакеты}
\label{sec:bundles}

Пакеты --- это ассоциативные массивы, то есть общие контейнеры для
любого набора данных Hansl (включая другие пакеты), в которых каждый
элемент идентифицируется строкой. Пользователи Python называют это
словарями; в C ++ и Java они называются картами; в Perl они известны
как хеши. Мы называем их пакетами, \emph{bundles}. Каждый элемент,
помещенный в пакет, связан с ключом, который можно использовать для
его восстановления в дальнейшем.  Для того, чтобы использовать пакет,
вы сначала либо «объявляете» его, как действующий:
%
\begin{code}
bundle foo
\end{code}
%
или как пустой, используя \texttt{null}:
%
\begin{code}
bundle foo = null
\end{code}
%
Эти две формулировки эквивалентны в том смысле, что они создают пустой
пакет. Разница заключается в том, что второй вариант можно
использовать повторно. Если пакет с именем \texttt{foo} уже
существует, результатом будет его очищение. Первый вариант может
использоваться только один раз в данном сеансе gretl; задать уже
существующую переменную не получится.  Чтобы добавить объект в пакет,
вы назначаете значение слева в данном составе: имя пакета с
последующим ключом. Наиболее распространенный способ присоединить ключ
к имени пакета с точкой, как в
\begin{code}
  foo.matrix1 = m
\end{code}
где добавляется объект с именем \texttt{m} (предположительно матрица),
чтобы связать \texttt{foo} с ключом \texttt{matrix1}. Ключ должен
соответствовать правилам определения имени переменной gretl (максимум
31 символ, начинается с буквы и состоит лишь из букв, цифр или нижнего
подчеркивания).  Альтернативный способ добиться того же эффекта ---
указать ключ в виде строкового литерала в кавычках, заключенного в
квадратные скобки, как в quoted string literal enclosed in square
brackets, as in
\begin{code}
  foo["matrix1"] = m
\end{code}
При использовании более сложного синтаксиса ключи не обязательно
должны быть написаны как имена переменных --- например, они могут
содержать пробелы, но их длина по-прежнему ограничена 31 символом.
Чтобы исключить элемент из пакета, снова используйте имя пакета, за
которым следует ключ, как в

\begin{code}
matrix bm = foo.matrix1
# или используйте более длинный вариант 
matrix m = foo["matrix1"]
\end{code}
Обратите внимание, что ключ, определяющий объект в данном пакете,
обязательно уникален. Если вы повторно используете существующий ключ в
новом назначении, результатом будет замена объекта, который был ранее
сохранен под данный ключ. Необязательно, чтобы тип заменяемого объекта
совпадал с именем изначального объекта.  Более быстрый способ, впервые
представленный в gretl 2017b --- использовать функцию \cmd{defbundle},
как в

\begin{code}
  bundle b = defbundle("s", "Sample string", "m", I(3))
\end{code}
где каждый аргумент с нечетным номером должен оцениваться как строка
(ключ), а каждый аргумент с четным номером должен оцениваться как
объект данного типа, который может быть включен в пакет.  Обратите
внимание, что когда вы добавляете объект в пакет, на самом деле
происходит получение пакетом копии объекта. Внешний объект сохраняет
свою идентичность и не изменяется, если связанный объект заменяется
другим. Рассмотрим следующий фрагмент скрипта:

\begin{code}
bundle foo
matrix m = I(3)
foo.mykey = m
scalar x = 20
foo.mykey = x
\end{code}
После выполнения вышеуказанных команд в пакете \texttt{foo} не будет
матрицы под \texttt{mykey}, но исходная матрица \texttt{m} все еще в
отличном состоянии. Чтобы удалить объект из пакета, используйте
команду удаления с комбинацией пакет/ключ, как в
\begin{code}
delete foo.mykey
delete foo["quoted key"]
\end{code}
Данная команда уничтожает объект, связанный с ключом, и удаляет ключ
из хэш-таблицы\footnote{На самом деле пакеты gretl имеют форму
  хеш-таблицы \textsf{GLib}.}.  Помимо добавления, использования,
замены и удаления отдельных элементов, другие поддерживаемые операции
для пакетов включают объединение и вывод. Что касается объединения,
если определены пакеты \texttt{b1} и \texttt{b2}, можно написать

\begin{code}
bundle b3 = b1 + b2
\end{code}

чтобы создать новый пакет, который представляет собой объединение двух
других. Алгоритм такой: создать новый пакет (копия \texttt{b1}), затем
добавить любые элементы из \texttt{b2}, ключи которых еще не
присутствуют в новом пакете. Это означает, что объединение пакетов не
обязательно коммутативно (результат может зависеть от перестановки
элементов), если пакеты имеют одну или более общих ключевых строк.
Если \texttt{b} --- это пакет, и вы даете команду \texttt{print b},
далее вы получите список ключей пакета вместе с типами соответствующих
объектов, как в
\begin{code}
? print b
bundle b:
 x (scalar)
 mat (matrix)
 inside (bundle)
\end{code}

\subsection{Использование пакета}
\label{sec:bundle-usage}

Чтобы проиллюстрировать, как пакет сохраняет информацию, мы будем
использовать метод обыкновенных наименьших квадратов (OLS): в качестве
примера следующий код оценивает регрессию OLS и сохраняет все
результаты в пакет:

\begin{code}
/* предположим, что для y и X даны T x 1 и T x k матрицы */

bundle my_model = null               # инициализация
my_model.T = rows(X)                 # размер выборки
my_model.k = cols(X)                 # кол-во регрессоров
matrix e                             # содержит остатки
b = mols(y, X, &e)                   # запуск OLS через собств. функцию
s2 = meanc(e.^2)                     # оценка разброса выборки
matrix V = s2 .* invpd(X'X)          # вывод матрицы ковариаций

/* теперь сохраняем оцененные параметры в пакет */

my_model.betahat = b
my_model.s2 = s2
my_model.vcv = V
my_model.stderr = sqrt(diag(V))
\end{code}

Полученный таким образом пакет представляет собой контейнер, который
можно использовать для любых целей. Например, следующий фрагмент кода
показывает, как использовать пакет с той же структурой для выполнения
вневыборочного прогноза. Представьте, что $k=4$ и значение
$\mathbf{x}$ , для которого мы хотим прогноз $y$ , равно
\[
  \mathbf{x}' = [ 10 \quad 1  \quad -3 \quad 0.5 ]
\]
Прогнозные формулы будут иметь следующий вид:
\begin{eqnarray*}
  \hat{y}_f & = & \mathbf{x}'\hat{\beta} \\
  s_f & = & \sqrt{\hat{\sigma}^2 + \mathbf{x}'V(\hat{\beta})\mathbf{x}} \\
  CI & = & \hat{y}_f \pm 1.96 s_f 
\end{eqnarray*}
где $CI$ (приблизительный) 95-процентный доверительный
интервал. Приведенные выше формулы переводятся в
\begin{code}
  x = { 10, 1, -3, 0.5 }
  scalar ypred    = x * my_model.betahat
  scalar varpred  = my_model.s2 + qform(x, my_model.vcv)
  scalar sepred   = sqrt(varpred)
  matrix CI_95    = ypred + {-1, 1} .* (1.96*sepred)
  print ypred CI_95
\end{code}

\section{Массивы}
\label{sec:arrays}

Массив gretl --- это контейнер, который может содержать ноль или более
объектов определенного типа, индексированных как последовательные
целые числа, начиная с 1. Он одномерный. Этот тип реализован довольно
«общим» бэк-ендом. В массивы можно помещать следующие типы объектов:
строки, матрицы, пакеты и списки; один массив может содержать только
один из этих типов.

\subsection{Операции с массивами}

Следующее, как мы полагаем, не требует пояснений:

\begin{code}
strings S1 = array(3)
matrices M = array(4)
strings S2 = defarray("fish", "chips")
S1[1] = ":)"
S1[3] = ":("
M[2] = mnormal(2,2)
print S1
eval inv(M[2])
S = S1 + S2
print S
\end{code}

\texttt{Array()} принимает целочисленный аргумент для размера массива;
функция \texttt{defarray()} обозначает количество аргументов (один или
несколько), каждый из которых может быть именем переменной данного
типа или выражением, оценивающим объект данного типа. Соответствующий
результат будет следующим:

\begin{code}
Array of strings, length 3
[1] ":)"
[2] null
[3] ":("

     0.52696      0.28883 
    -0.15332     -0.68140 

Array of strings, length 5
[1] ":)"
[2] null
[3] ":("
[4] "fish"
[5] "chips"
\end{code}

Чтобы узнать количество элементов в массиве, вы можете использовать функцию
\texttt{nelem()}.

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "hansl-primer"
%%% End: 

