Есть ли способ записи в целую строку / столбец матрицы налгебры? - PullRequest
1 голос
/ 24 июня 2019

Я использую структуру DMatrix для выделения матриц динамического размера, где я многократно перезаписываю каждый столбец нормализованным вектором столбца, используя L2-норму.

// a is some DMatrix of arbitrary size
let col_0 = a.column(0);
let norm_of_col_0 = col_0.normalize();

Вместо того, чтобы зацикливаться на каждой ячейке в текущем столбце:

let row = a.shape().0;
let col = a.shape().1;
for col in 0..ncols {
    let norm_of_col = a.column(col).normalize();
    for row in 0..nrows {
        *a.index_mut((row, col)) = norm_of_col()[row];
    }
}

Я бы хотел перезаписать столбец его нормализованной версией.Код должен семантически выглядеть примерно так:

*a.index_mut((_, col)) = norm_of_col();

, где (_, col) означает, что я выбираю столбец col, а _ означает всю строку.

В общем,Есть ли способ перезаписать строку или столбец новой строкой или столбцом того же размера и типа данных?Методы как insert_columns только добавляют столбцы в существующую матрицу.

Если это так, то в вычислительном отношении это выполняется быстрее или я должен просто написать вспомогательный метод, который перебирает каждую ячейку для обновления матрицы?

1 Ответ

1 голос
/ 25 июня 2019

Вы можете сделать это следующим образом: nalgebra 0.18.0:

use nalgebra::DMatrix;

fn main() {
    let mut m = DMatrix::from_vec(2, 3, (0 .. 6).map(|n| n as f64).collect());
    dbg!(&m);
    for mut col in m.column_iter_mut() {
        let normalized = col.normalize();
        col.copy_from(&normalized);
    }
    dbg!(&m);
}

Я не измерял производительность этого кода по сравнению с вашим.

Обратите внимание, что copy_from проходит пункты без проверки границ на каждом шаге, вместо этого делая проверки только один раз перед циклом.Я не проверял, может ли оптимизатор выполнить эквивалентное преобразование в вашем коде.Этот простой тест дает преимущество в ответе на моем компьютере (не уверен, насколько он репрезентативен; применяется обычный отказ от ответственности за тестирование):

use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion};
use nalgebra::DMatrix;

fn normalize_lib(m: &mut DMatrix<f64>) {
    for mut col in m.column_iter_mut() {
        let normalized = col.normalize();
        col.copy_from(&normalized);
    }
}

fn normalize_hand_rolled(a: &mut DMatrix<f64>) {
    let nrows = a.shape().0;
    let ncols = a.shape().1;
    for col in 0..ncols {
        let norm_of_col = a.column(col).normalize();
        for row in 0..nrows {
            *a.index_mut((row, col)) = norm_of_col[row];
        }
    }
}

fn benchmark(c: &mut Criterion) {
    let mut m0 = DMatrix::new_random(100, 100);
    let mut m1 = m0.clone();
    let bench = Benchmark::new("lib", move |b| b.iter(|| normalize_lib(black_box(&mut m0))))
        .with_function("hand_rolled", move |b| {
            b.iter(|| normalize_hand_rolled(black_box(&mut m1)))
        });
    c.bench("normalize", bench);
}

criterion_group!(benches, benchmark);
criterion_main!(benches);
normalize/lib           time:   [26.102 us 26.245 us 26.443 us]
normalize/hand_rolled   time:   [37.013 us 37.057 us 37.106 us]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...