Линейная алгебра

Сложение матриц

ndarray-badge cat-science-badge

Создаёт две двумерные матрицы (2-D) с помощью ndarray::arr2 и суммирует их поэлементно.

Обратите внимание, что сумма вычисляется как let sum = &a + &b. Оператор & используется, чтобы избежать поглощения a и b и сделать их доступными для отображения позже. Создаётся новый массив, содержащий их сумму.

extern crate ndarray;

use ndarray::arr2;

fn main() {
    let a = arr2(&[[1, 2, 3],
                   [4, 5, 6]]);

    let b = arr2(&[[6, 5, 4],
                   [3, 2, 1]]);

    let sum = &a + &b;

    println!("{}", a);
    println!("+");
    println!("{}", b);
    println!("=");
    println!("{}", sum);
}

Перемножение матриц

ndarray-badge cat-science-badge

Создаёт две матрицы с помощью ndarray::arr2 и выполняет перемножение матриц с помощью ndarray::ArrayBase::dot.

extern crate ndarray;

use ndarray::arr2;

fn main() {
    let a = arr2(&[[1, 2, 3],
                   [4, 5, 6]]);
    let b = arr2(&[[6, 3],
                   [5, 2],
                   [4, 1]]);

    println!("{}", a.dot(&b));
}

Умножение скаляра на вектор и на матрицу

ndarray-badge cat-science-badge

Создаёт одномерный 1-D массив (вектор) с помощью ndarray::arr1 и двумерных 2-D массив (матрицу) с помощью ndarray::arr2.

Сначала скаляр умножается на вектор, чтобы получить другой вектор. Затем матрица умножается на новый вектор с помощью ndarray::Array2::dot. (Матричное умножение выполняется с использованием метода dot, а оператор * выполняет поэлементное умножение.)

В ndarray массивы можно интерпретировать как либо векторы строк, либо столбцов, в зависимости от контекста. Если важно представить ориентацию вектора, необходимо использовать двумерный массив с одной строкой или одним столбцом. В этом примере вектор является 1-D массивом справа, поэтому dot обрабатывает его как вектор столбца.

extern crate ndarray;
use ndarray::{arr1, arr2, Array1};
fn main() {
    let scalar = 4;
    let vector = arr1(&[1, 2, 3]);
    let matrix = arr2(&[[4, 5, 6],
                        [7, 8, 9]]);
    let new_vector: Array1<_> = scalar * vector;
    println!("{}", new_vector);
    let new_matrix = matrix.dot(&new_vector);
    println!("{}", new_matrix);
}

Сравнение вектора

ndarray-badge

Крейт ndarray поддерживает несколько способов создания массивов - этот рецепт создаёт ndarray::Array массивы из std::Vec, используя from. Затем он суммирует массивы поэлементно.

Этот рецепт содержит пример поэлементного сравнения двух векторов с плавающей точкой. Числа с плавающей точкой часто хранятся неточно, что затрудняет точное сравнение. Тем не менее, assert_abs_diff_eq! макрос из крейта approx позволяет удобное, поэлементное сравнение. Для того, чтобы использовать approx крейта с ndarray, то функция approx должна быть добавлена к ndarray зависимости в Cargo.toml. Например, ndarray = { version = "0.13", features = ["approx"] } .

Этот рецепт также содержит дополнительные примеры владения. Здесь let z = a + b потребляет a и b, обновляет переменную a результатом, а затем переносит владение в z. В качестве альтернативы, let w = &c + &d создает новый вектор без использования c или d, что позволяет их модифицировать позже. См. Бинарные операторы с двумя массивами для дополнительной информации.

#[macro_use(assert_abs_diff_eq)]
extern crate approx;
extern crate ndarray;

use ndarray::Array;

fn main() {
  let a = Array::from(vec![1., 2., 3., 4., 5.]);
  let b = Array::from(vec![5., 4., 3., 2., 1.]);
  let mut c = Array::from(vec![1., 2., 3., 4., 5.]);
  let mut d = Array::from(vec![5., 4., 3., 2., 1.]);
  let z = a + b;
  let w =  &c + &d;
  assert_abs_diff_eq!(z, Array::from(vec![6., 6., 6., 6., 6.]));
  println!("c = {}", c);
  c[0] = 10.;
  d[1] = 10.;
  assert_abs_diff_eq!(w, Array::from(vec![6., 6., 6., 6., 6.]));
}

Норма вектора

ndarray-badge

Этот рецепт демонстрирует использование типа Array1, типа ArrayView1, метода fold, метода dot при вычислении нормы l1 и [l2] для данного вектора.

  • Функция l2_norm является более простой из двух, так как она вычисляет квадратный корень из точечного произведения вектора с самим собой.
  • Функция l1_norm вычисляется с помощью операции fold, которая суммирует абсолютные значения элементов. (Это также может быть выполнено с помощью x.mapv(f64::abs).scalar_sum(), но это выделит новый массив для результата mapv.)

Обратите внимание, что и l1_norm и l2_norm принимают аргумент типа ArrayView1. Этот рецепт учитывает векторные нормы, поэтому функции норм должны принимать только одномерные представления (следовательно, ArrayView1 ). Хотя функции могут принимать параметр типа &Array1<f64>, это потребует от вызывающей стороны иметь ссылку на собственный массив, что является более ограничительным, чем просто доступ к представлению (поскольку представление может быть создано из любого массива или просмотр, а не просто принадлежащий массив).

Типы Array и ArrayView являются псевдонимами для типов ArrayBase. Таким образом, наиболее общий тип аргумента для вызывающей стороны будет &ArrayBase<S, Ix1> where S: Data, потому что когда вызывающая сторона может использовать &array или & view вместо x.view(). Если функция является частью публичного API, это может быть лучшим выбором для удобства пользователей. Для внутренних функций предпочтительным может быть более лаконичный ArrayView1<f64>.

#[macro_use(array)]
extern crate ndarray;

use ndarray::{Array1, ArrayView1};

fn l1_norm(x: ArrayView1<f64>) -> f64 {
    x.fold(0., |acc, elem| acc + elem.abs())
}

fn l2_norm(x: ArrayView1<f64>) -> f64 {
    x.dot(&x).sqrt()
}

fn normalize(mut x: Array1<f64>) -> Array1<f64> {
    let norm = l2_norm(x.view());
    x.mapv_inplace(|e| e/norm);
    x
}

fn main() {
    let x = array![1., 2., 3., 4., 5.];
    println!("||x||_2 = {}", l2_norm(x.view()));
    println!("||x||_1 = {}", l1_norm(x.view()));
    println!("Normalizing x yields {:?}", normalize(x));
}

[l2]: https://docs.rs/ndarray/*/ndarray/type.ArrayView1.html ## Инвертирование матрицы

nalgebra-badge cat-science-badge

Создаёт матрицу 3x3 с помощью nalgebra::Matrix3 и инвертирует её, если возможно.

extern crate nalgebra;

use nalgebra::Matrix3;

fn main() {
    let m1 = Matrix3::new(2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 2.0, 1.0, 2.0);
    println!("m1 = {}", m1);
    match m1.try_inverse() {
        Some(inv) => {
            println!("The inverse of m1 is: {}", inv);
        }
        None => {
            println!("m1 is not invertible!");
        }
    }
}