Создание и инициализация матриц и векторов

Предусмотрено несколько способов объявления и инициализации матриц и векторов. Их можно условно разделить на несколько категорий по своему назначению:

  • объявление без указания размера;
  • объявление с указанием размера;
  • объявление с инициализацией;
  • статические методы создания;
  • нестатические методы (пере-)конфигурирования и инициализации.

Самый простой метод создания — это объявление без указания размера, то есть без распределения памяти для данных. Для этого достаточно указать тип и имя переменной:

matrix         matrix_a;   // матрица типа double
matrix<doublematrix_a1;  // матрица типа double внутри шаблонов функций или классов
matrix<float>  matrix_a2;  // матрица типа float
vector         vector_v;   // вектор типа double
vector<doublevector_v1;  // другая запись создания вектора типа double 
vector<float>  vector_v2;  // вектор типа float

Далее вы можете изменить размер созданных объектов и заполнить нужными значениями. Также их можно использовать во встроенных методах матриц и векторов для получения результатов вычислений. Все эти методы будут рассмотрены по группам в разделах этой главы.

Можно объявить матрицу или вектор с указанием размера. При этом произойдет распределение памяти, но без какой-либо инициализации. Для этого после имени переменной в круглых скобках задаем размер(ы) (для матрицы — сначала количество строк, затем количество столбцов):

matrix         matrix_a(128128);      // в качестве параметров можно указывать
matrix<doublematrix_a1(nRowsnCols); //       как константы, так и переменные
matrix<float>  matrix_a2(nRows1);     // аналог вектора-столбца
vector         vector_v(256);
vector<doublevector_v1(nSize);
vector<float>  vector_v2(nSize + 16);   // выражение в качестве параметра

Третий способ создания объектов — объявление с инициализацией. Размеры матриц и векторов в этом случае определяются инициализирующей последовательностью, указанной в фигурных скобках:

matrix         matrix_a = {{0.10.20.3}, {0.40.50.6}};
matrix<doublematrix_a1 = matrix_a;    // должны быть матрицы одного и того же типа
matrix<float>  matrix_a2 = {{12}, {34}};
vector         vector_v = {-5, -4, -3, -2, -1012345};
vector<doublevector_v1 = {152.43.3};
vector<float>  vector_v2 = vector_v1;   // должны быть векторы одного и того же типа

Существуют также статические методы создания матриц и векторов указанного размера с инициализацией определённым способом (под ту или иную каноническую форму). Все они приведены в списке ниже и имеют схожие прототипы (векторы отличаются от матриц только отсутствием второго размера).

static matrix<T> matrix<T>::Eye∫Tri(const ulong rows, const ulong cols, const int diagonal = 0);

static matrix<T> matrix<T>::Identity∫Ones∫Zeros(const ulong rows, const ulong cols);

static matrix<T> matrix<T>::Full(const ulong rows, const ulong cols, const double value);

  • Eye — создает матрицу с единицами по указанной диагонали и нулями в остальных местах;
  • Tri — создает матрицу с единицами по указанной диагонали и ниже нее, и нулями в остальных местах;
  • Identity — создает единичную матрицу указанного размера;
  • Ones — создает матрицу (или вектор), заполненную единицами;
  • Zeros — создает матрицу (или вектор), заполненную нулями;
  • Full — создает матрицу (или вектор), заполненную заданным значением во всех элементах.

При необходимости можно "превратить" любую уже существующую матрицу в единичную, для чего к ней следует применить нестатический метод Identity (без параметров).

Продемонстрируем методы в действии:

matrix         matrix_a = matrix::Eye(451);
matrix<doublematrix_a1 = matrix::Full(34M_PI);
matrixf        matrix_a2 = matrixf::Identity(55);
matrixf<floatmatrix_a3 = matrixf::Ones(55);
matrix         matrix_a4 = matrix::Tri(45, -1);
vector         vector_v = vector::Ones(256);
vectorf        vector_v1 = vector<float>::Zeros(16);
vector<float>  vector_v2 = vectorf::Full(128float_value);

Кроме того, существуют нестатические методы для инициализации матрицы/вектора заданными значениями — Init и Fill.

void matrix<T>::Init(const ulong rows, const ulong cols, func_reference rule = NULL, ...)

void matrix<T>::Fill(const T value)

Важным достоинством метода Init (впрочем, как и конструкторов) является возможность указать в параметрах инициализирующую функцию для заполнения элементов матрицы/вектора по заданному закону (см. пример чуть ниже).

Ссылку на такую функцию можно передать после размеров, указав её идентификатор без кавычек в параметре rule (это не указатель в смысле typedef (*pointer)(...) и не строка с именем).

Инициализирующая функция должна иметь первым параметром ссылку на заполняемый объект, а также может иметь дополнительные параметры: в этом случае значения для них передаются в Init или конструктор после ссылки на саму функцию. Без указания rule-ссылки будет просто создана матрица заданных размеров.

Метод Init позволяет заодно изменить конфигурацию матрицы.

Покажем все изложенное на небольших примерах.

matrix m(22);
m.Fill(10);
Print("matrix m \n"m);
/*
  matrix m
  [[10,10]
  [10,10]]
*/
m.Init(46);
Print("matrix m \n"m);
/*
  matrix m
  [[10,10,10,10,0.0078125,32.00000762939453]
  [0,0,0,0,0,0]
  [0,0,0,0,0,0]
  [0,0,0,0,0,0]]
*/

Здесь метод Init был использован для изменения размеров уже инициализированной матрицы, что привело к заполнению новых элементов случайными значениями.

А следующая функция заполняет матрицу числами, увеличивающимся в геометрической прогрессии:

template<typename T>
void MatrixSetValues(matrix<T> &mconst T initial = 1)
{
   T value = initial;
   for(ulong r = 0r < m.Rows(); r++)
   {
      for(ulong c = 0c < m.Cols(); c++)
      {
         m[r][c] = value;
         value *= 2;
      }
   }
}

Тогда её можно применить для создания матрицы.

void OnStart()
{
   matrix M(36MatrixSetValues);
   Print("M = \n"M);
}

Результат выполнения:

M = 
[[1,2,4,8,16,32]
 [64,128,256,512,1024,2048]
 [4096,8192,16384,32768,65536,131072]]

В данном случае значения для параметра инициализирующей функции не были указаны следом за её идентификатором в вызове конструктора, и потому использовалось значение по умолчанию (1). Но мы можем, например, для той же MatrixSetValues передать стартовое значение -1, что приведет к заполнению матрицы отрицательным рядом.

   matrix M(36MatrixSetValues, -1);