File size: 3,891 Bytes
be99550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// ๐Ÿš€ ๋Œ€๊ทœ๋ชจ 100๋งŒ ๋…ธ๋“œ(1024x1024) ๋ณ‘๋ ฌ ๋ณต์žก๊ณ„ ์—”์ง„ (src/parallel_engine.rs)
use rayon::prelude::*;
use rand::Rng;

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(u8)]
pub enum PhaseState {
    HyperInhibition = 0,
    StandardInhibition = 1,
    SubInhibition = 2,
    NegQuiescent = 3,
    PosQuiescent = 4,
    SubExcitation = 5,
    StandardExcitation = 6,
    HyperExcitation = 7,
}

impl PhaseState {
    #[inline(always)]
    pub fn value(&self) -> f32 {
        match self {
            PhaseState::HyperInhibition    => -2.0,
            PhaseState::StandardInhibition => -1.0,
            PhaseState::SubInhibition     => -0.5,
            PhaseState::NegQuiescent       => -0.01,
            PhaseState::PosQuiescent       =>  0.01,
            PhaseState::SubExcitation      =>  0.5,
            PhaseState::StandardExcitation =>  1.0,
            PhaseState::HyperExcitation    =>  2.0,
        }
    }

    #[inline(always)]
    pub fn from_energy(e: f32) -> Self {
        if e <= -1.5 { PhaseState::HyperInhibition }
        else if e <= -0.75 { PhaseState::StandardInhibition }
        else if e <= -0.25 { PhaseState::SubInhibition }
        else if e <= 0.0 { PhaseState::NegQuiescent }
        else if e <= 0.25 { PhaseState::PosQuiescent }
        else if e <= 0.75 { PhaseState::SubExcitation }
        else if e <= 1.5 { PhaseState::StandardExcitation }
        else { PhaseState::HyperExcitation }
    }
}

pub struct LargeScaleEngine {
    pub size: usize,
    pub bedrock: Vec<f32>,
    pub topsoil: Vec<PhaseState>,
}

impl LargeScaleEngine {
    pub fn new(size: usize) -> Self {
        let mut rng = rand::thread_rng();
        let total_nodes = size * size;
        let bedrock: Vec<f32> = (0..total_nodes).map(|_| rng.gen_range(-0.5..0.5)).collect();
        let topsoil: Vec<PhaseState> = (0..total_nodes).map(|_| PhaseState::from_energy(rng.gen_range(-2.0..2.0))).collect();

        LargeScaleEngine { size, bedrock, topsoil }
    }

    /// Rayon ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๋ณ‘๋ ฌ ์ƒํƒœ ์ „์ด (100๋งŒ ๋…ธ๋“œ ๋ถ„ํ•  ์ฒ˜๋ฆฌ)
    pub fn step_parallel(&mut self) -> f32 {
        let size = self.size;
        let prev_topsoil = &self.topsoil;
        let bedrock = &self.bedrock;

        // ์ฒญํฌ(Row) ๋‹จ์œ„ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๋ณ‘๋ ฌ ๊ฐฑ์‹ 
        let (next_topsoil, total_energy): (Vec<PhaseState>, f32) = (0..size)
            .into_par_iter()
            .map(|y| {
                let mut row_states = Vec::with_capacity(size);
                let mut row_energy = 0.0f32;
                let s = size as i32;

                for x in 0..size {
                    let idx = y * size + x;
                    let up_idx = ((y as i32 - 1 + s) % s * s + x as i32) as usize;
                    let down_idx = ((y as i32 + 1) % s * s + x as i32) as usize;
                    let left_idx = (y as i32 * s + (x as i32 - 1 + s) % s) as usize;
                    let right_idx = (y as i32 * s + (x as i32 + 1) % s) as usize;

                    let neighbor_e = (
                        prev_topsoil[up_idx].value() +
                        prev_topsoil[down_idx].value() +
                        prev_topsoil[left_idx].value() +
                        prev_topsoil[right_idx].value()
                    ) * 0.25;

                    let local_field = neighbor_e + bedrock[idx];
                    row_states.push(PhaseState::from_energy(local_field));
                    row_energy += local_field.abs();
                }
                (row_states, row_energy)
            })
            .reduce(
                || (Vec::with_capacity(size * size), 0.0f32),
                |mut acc, (row_states, row_e)| {
                    acc.0.extend(row_states);
                    acc.1 += row_e;
                    acc
                },
            );

        self.topsoil = next_topsoil;
        total_energy / (size * size) as f32
    }
}