CodeBlanks Logo Icon CodeBlanks

SIMD matris

SIMD ile paralel matris çarpımı yaparsın.

Bitirme görevi: SIMD matris

4×4 matris-vektör çarpımını SIMD dostu biçimde yaz. Klasik satır-nokta yaklaşımı her satırda yatay bir indirgeme gerektirir. Sütun yaklaşımı ise yalnızca dikey işlemler kullanır: sonuç vektörü, her sütunun ilgili x bileşeniyle çarpılıp toplanmasıdır (y += sütun_j * x[j], "axpy"):

// y = A·x, A sütun düzeninde: a[j] = j. sütun
fn matvec(a: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
    let mut y = [0.0f32; 4];
    for j in 0..4 {
        for i in 0..4 {          // 4 şeritli dikey çarp-topla
            y[i] += a[j][i] * x[j];
        }
    }
    y
}

İç döngü doğrudan tek bir 4 şeritli çarp-topla talimatına eşlenir; yatay işlem gerekmez.

Doğrulama

Optimize edilmiş bir çekirdek her zaman basit bir referans uygulamayla karşılaştırılmalıdır. Satır düzenli matrisle aynı sonucu veren bir referans:

fn matvec_ref(satirlar: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
    satirlar.map(|r| r.iter().zip(&x).map(|(a, b)| a * b).sum())
}

// sütun düzenine çevirmek: devrik
fn devrik(m: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
    std::array::from_fn(|j| std::array::from_fn(|i| m[i][j]))
}

Uygulama Matris-vektör

Yukarıdaki matvec, matvec_ref ve devrik fonksiyonlarını yaz. Satır düzeninde [[1,2,0,0],[0,1,0,0],[0,0,2,0],[0,0,0,3]] ve x = [1, 1, 1, 1] için matvec(devrik(A), x) sonucunu {:?} ile ve referansla eşitliğini boşlukla yazdır.

Başlangıç kodu

main.rs
fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
fn matvec(a: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
    let mut y = [0.0f32; 4];
    for j in 0..4 {
        for i in 0..4 {
            y[i] += a[j][i] * x[j];
        }
    }
    y
}

fn matvec_ref(satirlar: [[f32; 4]; 4], x: [f32; 4]) -> [f32; 4] {
    satirlar.map(|r| r.iter().zip(&x).map(|(a, b)| a * b).sum())
}

fn devrik(m: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
    std::array::from_fn(|j| std::array::from_fn(|i| m[i][j]))
}

fn main() {
    let a = [
        [1.0, 2.0, 0.0, 0.0],
        [0.0, 1.0, 0.0, 0.0],
        [0.0, 0.0, 2.0, 0.0],
        [0.0, 0.0, 0.0, 3.0],
    ];
    let x = [1.0; 4];
    let y = matvec(devrik(a), x);
    println!("{:?} {}", y, y == matvec_ref(a, x));
}

Beklenen çıktı

[3.0, 1.0, 2.0, 3.0] true

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Sütun düzeninde depolamanın bu çarpım için avantajı nedir?

  • Daha az bellek
  • Daha kolay yazılır
  • Avantajı yok
  • Her sütun bellekte ardışıktır; tek yüklemeyle bir vektöre sığar Doğru cevap

Açıklama: Veri düzenini algoritmaya göre seçmek, SIMD performansının çoğunu belirler.

2 Dikey çarp-topla

Soru
for j in 0..4 {
    for i in 0..4 {
        y[i] += a[j][i] * x[____];
    }
}
Cevap
for j in 0..4 {
    for i in 0..4 {
        y[i] += a[j][i] * x[j];
    }
}

Açıklama: sütunun her şeridi aynı x[j] ile çarpılır.

3 Yaklaşım ve özelliği

Kavram Anlamı
Satır-nokta Yatay indirgeme ister
Sütun axpy Yalnızca dikey
Referans uygulama Doğrulama
Devrik Düzen dönüşümü

Uzman bölümündeki tüm dersler