Индексация начинается с 0, как и для массивов в Ruby. Возможно, это противоречит вашему опыту работы с матрицами, но индексация с 1 в качестве альтернативы не предусмотрена. Можно реализовать эту возможность самостоятельно:

# Наивный подход... не поступайте так!

class Matrix

 alias bracket []

 def [] (i,j)

  bracket(i-1,j-1)

 end

end

m = Matrix[[1,2,3],[4,5,6],[7,8,9]]

p m[2,2] # 5

На первый взгляд, этот код должен работать. Большинство операций над матрицами даже будет давать правильный результат при такой индексации. Так в чем же проблема? В том, что мы не знаем деталей внутренней реализации класса Matrix. Если в нем для доступа к элементам матрицы всегда используется собственный метод [], то все будет хорошо. Но если где-нибудь имеются прямые обращения к внутреннему массиву или применяются иные оптимизированные решения, то возникнет ошибка. Поэтому, решившись на такой трюк, вы должны тщательно протестировать новое поведение.

К тому же необходимо изменить методы row и vector. В них индексы тоже начинаются с 0, но метод [] не вызывается. Я не проверял, что еще придется модифицировать.

Иногда необходимо узнать размерность или форму матрицы. Для этого есть разные методы, например row_size и column_size.

Метод row_size возвращает число строк в матрице. Что касается метода column_size, тут есть одна тонкость: он проверяет лишь размер первой строки. Если по каким-либо причинам матрица не прямоугольная, то полученное значение бессмысленно. Кроме того, поскольку метод square? (проверяющий, является ли матрица квадратной) обращается к row_size и column_size, его результат тоже нельзя считать стопроцентно надежным.

m1 = Matrix[[1,2,3],[4,5,6],[7,8,9]]

m2 = Matrix[[1,2,3],[4,5,6],[7,8]]

m1.row_.size   # 3

m1.column_size # 3 m2.row_size # 3

m2.column_size # 3 (неправильно)

m1.square?     # true

m2.square?     # true (неправильно)

Решить эту мелкую проблему можно, например, определив метод rectangular?.

class Matrix

 def rectangular?

  arr = to_a

  first = arr[0].size

  arr[1..-1].all? {|x| x.size == first }

 end

end

Можно, конечно, модифицировать метод square?, так чтобы сначала он проверял, является ли матрица прямоугольной. В таком случае нужно будет изменить метод column_size, чтобы он возвращал nil для непрямоугольной матрицы.

Для вырезания части матрицы имеется несколько методов. Метод row_vectors возвращает массив объектов класса Vector, представляющих строки (см. обсуждение класса Vector ниже.) Метод column_vectors работает аналогично, но для столбцов. Наконец, метод minor возвращает матрицу меньшего размера; его параметрами являются либо четыре числа (нижняя и верхняя границы номеров строк и столбцов), либо два диапазона.

m = Matrix[[1,2,3,4],[5,6,7,8],[6,7,8,9]]

rows = m.row_vectors # Три объекта Vector.

cols = m.column_vectors # Четыре объекта Vector.

m2 = m.minor(1,2,1,2) # Matrix[[6,7,],[7,8]]

m3 = m.minor(0..1,1..3) # Matrix[[[2,3,4],[6,7,8]]

К матрицам применимы обычные операции: сложение, вычитание, умножение и деление. Для выполнения некоторых из них должны соблюдаться ограничения на размеры матриц-операндов; в противном случае будет возбуждено исключение (например, при попытке перемножить матрицы размерностей 3×3 и 4×4).

Поддерживаются стандартные преобразования: inverse (обращение), transpose (транспонирование) и determinant (вычисление определителя). Для целочисленных матриц определитель лучше вычислять с помощью библиотеки mathn (раздел 5.12).

Класс Vector — это, по существу, частный случай одномерной матрицы. Его объект можно создать с помощью методов [] или elements; в первом случае параметром является развернутый массив, а во втором — обычный массив и необязательный параметр сору (по умолчанию равный true).

arr = [2,3,4,5]

v1 = Vector[*arr]               # Vector[2,3,4,5]

v2 = Vector.elements(arr)       # Vector[2,3,4,5]

v3 = Vector.elements(arr,false) # Vector[2,3,4,5]

arr[2] = 7                      # теперь v3 - Vector[2,3,7,5].

Метод covector преобразует вектор длины N в матрицу размерности N×1 (выполняя попутно транспонирование).

v = Vector[2,3,4]

m = v.covector # Matrix[[2,3,4]]

Поддерживается сложение и вычитание векторов одинаковой длины. Вектор можно умножать на матрицу и на скаляр. Все эти операции подчиняются обычным математическим правилам.

v1 = Vector[2,3,4]

v2 = Vector[4,5,6]

v3 = v1 + v2        # Vector[6,8,10]

v4 = v1*v2.covector # Matrix![8,10,12],[12,15,18],[16,20,24]]

v5 = v1*5           # Vector[10,15,20]

Имеется метод inner_product (скалярное произведение):

v1 = Vector[2,3,4]

v2 = Vector[4,5,6]

x = v1.inner_product(v2) # 47

Дополнительную информацию о классах Matrix и vector можно найти в любом справочном руководстве, например воспользовавшись командной утилитой ri, или на сайте ruby-doc.org.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату