1pub fn moe_align_block_size_i32(
4 topk_ids: &[i32],
5 expert_count: usize,
6 block_size: usize,
7) -> (Vec<i32>, Vec<i32>, i32, Vec<i32>, i32) {
8 let sentinel = topk_ids.len() as i32;
9 let max_num_tokens_padded = topk_ids.len() + expert_count * (block_size - 1);
10 let mut sorted_token_ids = vec![sentinel; max_num_tokens_padded];
11 let mut cumsum = vec![0i32; expert_count + 1];
12 let mut total = 0usize;
13 let mut max_count = 0usize;
14 for (expert, cumsum_slot) in cumsum.iter_mut().enumerate().take(expert_count) {
15 *cumsum_slot = total as i32;
16 let mut count = 0usize;
17 for (token, &id) in topk_ids.iter().enumerate() {
18 if id == expert as i32 {
19 sorted_token_ids[total + count] = token as i32;
20 count += 1;
21 }
22 }
23 max_count = max_count.max(count);
24 total += ceil_div(count, block_size) * block_size;
25 }
26 cumsum[expert_count] = total as i32;
27 let expert_ids = (0..total / block_size)
28 .map(|block| {
29 let token_offset = (block * block_size) as i32;
30 cumsum
31 .windows(2)
32 .position(|range| token_offset >= range[0] && token_offset < range[1])
33 .unwrap_or(expert_count - 1) as i32
34 })
35 .collect::<Vec<_>>();
36 (
37 sorted_token_ids,
38 expert_ids,
39 total as i32,
40 cumsum,
41 max_count as i32,
42 )
43}
44
45pub fn fused_moe_f32(
46 input: &[f32],
47 weight: &[f32],
48 routed_weight: &[f32],
49 topk_ids: &[i32],
50 tokens: usize,
51 top_k: usize,
52 columns: usize,
53 reduction: usize,
54 mul_routed_weight: bool,
55) -> Vec<f32> {
56 let mut out = vec![0.0f32; tokens * top_k * columns];
57 for slot in 0..tokens * top_k {
58 let token = slot / top_k;
59 let expert = topk_ids[slot] as usize;
60 for column in 0..columns {
61 let mut sum = 0.0f32;
62 for reduction_index in 0..reduction {
63 let input_offset = token * reduction + reduction_index;
64 let weight_offset =
65 expert * columns * reduction + column * reduction + reduction_index;
66 sum += input[input_offset] * weight[weight_offset];
67 }
68 if mul_routed_weight {
69 sum *= routed_weight[slot];
70 }
71 out[slot * columns + column] = sum;
72 }
73 }
74 out
75}
76
77pub fn fused_moe_f8e4m3_block_scaled_f32(
78 input: &[u8],
79 weight: &[u8],
80 input_scales: &[f32],
81 weight_scales: &[f32],
82 routed_weight: &[f32],
83 topk_ids: &[i32],
84 tokens: usize,
85 top_k: usize,
86 _experts: usize,
87 columns: usize,
88 reduction: usize,
89 group_n: usize,
90 group_k: usize,
91 mul_routed_weight: bool,
92) -> Vec<f32> {
93 let k_groups = ceil_div(reduction, group_k);
94 let n_groups = ceil_div(columns, group_n);
95 let mut out = vec![0.0f32; tokens * top_k * columns];
96 for slot in 0..tokens * top_k {
97 let token = slot / top_k;
98 let expert = topk_ids[slot] as usize;
99 for column in 0..columns {
100 let mut sum = 0.0f32;
101 for reduction_index in 0..reduction {
102 let k_group = reduction_index / group_k;
103 let input_offset = token * reduction + reduction_index;
104 let weight_offset =
105 expert * columns * reduction + column * reduction + reduction_index;
106 let input_scale = input_scales[token * k_groups + k_group];
107 let weight_scale = weight_scales
108 [expert * n_groups * k_groups + (column / group_n) * k_groups + k_group];
109 sum += f8e4m3_value(input[input_offset])
110 * f8e4m3_value(weight[weight_offset])
111 * input_scale
112 * weight_scale;
113 }
114 if mul_routed_weight {
115 sum *= routed_weight[slot];
116 }
117 out[slot * columns + column] = sum;
118 }
119 }
120 out
121}
122
123pub fn ceil_div(lhs: usize, rhs: usize) -> usize {
124 lhs.div_ceil(rhs)
125}
126
127fn f8e4m3_value(value: u8) -> f32 {
128 let sign = if value & 0x80 == 0 { 1.0 } else { -1.0 };
129 let exponent = (value >> 3) & 0x0f;
130 let mantissa = value & 0x07;
131 if exponent == 0x0f && mantissa == 0x07 {
132 f32::NAN
133 } else if exponent == 0 {
134 if mantissa == 0 {
135 sign * 0.0
136 } else {
137 sign * (mantissa as f32 / 8.0) * 2f32.powi(-6)
138 }
139 } else {
140 sign * (1.0 + mantissa as f32 / 8.0) * 2f32.powi(exponent as i32 - 7)
141 }
142}