1#[derive(Debug)]
18pub struct EpRoutingTable {
19 pub local_token_indices: Vec<u32>,
21 pub local_expert_ids: Vec<u32>,
23 pub local_weights: Vec<f32>,
25 pub remote_token_indices: Vec<u32>,
27 pub remote_expert_ids: Vec<u32>,
29 pub remote_weights: Vec<f32>,
31}
32
33impl EpRoutingTable {
34 pub fn local_count(&self) -> usize {
36 self.local_token_indices.len()
37 }
38
39 pub fn remote_count(&self) -> usize {
41 self.remote_token_indices.len()
42 }
43
44 pub fn total_count(&self) -> usize {
46 self.local_count() + self.remote_count()
47 }
48}
49
50pub fn build_ep_routing_table(
67 gate_indices: &[u32],
68 gate_weights: &[f32],
69 num_tokens: usize,
70 top_k: usize,
71 local_expert_start: usize,
72 local_expert_end: usize,
73) -> EpRoutingTable {
74 let total = num_tokens * top_k;
75 assert_eq!(gate_indices.len(), total, "gate_indices length mismatch");
76 assert_eq!(gate_weights.len(), total, "gate_weights length mismatch");
77
78 let mut local_token_indices = Vec::with_capacity(total);
80 let mut local_expert_ids = Vec::with_capacity(total);
81 let mut local_weights = Vec::with_capacity(total);
82 let mut remote_token_indices = Vec::with_capacity(total);
83 let mut remote_expert_ids = Vec::with_capacity(total);
84 let mut remote_weights = Vec::with_capacity(total);
85
86 for token_idx in 0..num_tokens {
87 for k in 0..top_k {
88 let flat_idx = token_idx * top_k + k;
89 let expert_id = gate_indices[flat_idx];
90 let weight = gate_weights[flat_idx];
91 let eid = expert_id as usize;
92
93 if eid >= local_expert_start && eid < local_expert_end {
94 local_token_indices.push(token_idx as u32);
95 local_expert_ids.push(expert_id);
96 local_weights.push(weight);
97 } else {
98 remote_token_indices.push(token_idx as u32);
99 remote_expert_ids.push(expert_id);
100 remote_weights.push(weight);
101 }
102 }
103 }
104
105 EpRoutingTable {
106 local_token_indices,
107 local_expert_ids,
108 local_weights,
109 remote_token_indices,
110 remote_expert_ids,
111 remote_weights,
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn test_all_local() {
121 let indices = vec![3u32, 7, 100, 200];
123 let weights = vec![0.6f32, 0.4, 0.55, 0.45];
124 let table = build_ep_routing_table(&indices, &weights, 2, 2, 0, 256);
125
126 assert_eq!(table.local_count(), 4);
127 assert_eq!(table.remote_count(), 0);
128 assert_eq!(table.total_count(), 4);
129 assert_eq!(table.local_token_indices, vec![0, 0, 1, 1]);
130 assert_eq!(table.local_expert_ids, vec![3, 7, 100, 200]);
131 }
132
133 #[test]
134 fn test_all_remote() {
135 let indices = vec![300u32, 400, 256, 511];
137 let weights = vec![0.6f32, 0.4, 0.55, 0.45];
138 let table = build_ep_routing_table(&indices, &weights, 2, 2, 0, 256);
139
140 assert_eq!(table.local_count(), 0);
141 assert_eq!(table.remote_count(), 4);
142 assert_eq!(table.remote_token_indices, vec![0, 0, 1, 1]);
143 assert_eq!(table.remote_expert_ids, vec![300, 400, 256, 511]);
144 }
145
146 #[test]
147 fn test_mixed_routing() {
148 let indices = vec![
151 10u32, 300, 255, 256, 400, 500, ];
155 let weights = vec![0.7f32, 0.3, 0.5, 0.5, 0.6, 0.4];
156 let table = build_ep_routing_table(&indices, &weights, 3, 2, 0, 256);
157
158 assert_eq!(table.local_count(), 2);
159 assert_eq!(table.remote_count(), 4);
160 assert_eq!(table.local_token_indices, vec![0, 1]);
161 assert_eq!(table.local_expert_ids, vec![10, 255]);
162 assert_eq!(table.local_weights, vec![0.7, 0.5]);
163 assert_eq!(table.remote_token_indices, vec![0, 1, 2, 2]);
164 assert_eq!(table.remote_expert_ids, vec![300, 256, 400, 500]);
165 assert_eq!(table.remote_weights, vec![0.3, 0.5, 0.6, 0.4]);
166 }
167
168 #[test]
169 fn test_rank1_perspective() {
170 let indices = vec![
172 10u32, 300, 255, 256, ];
175 let weights = vec![0.7f32, 0.3, 0.5, 0.5];
176 let table = build_ep_routing_table(&indices, &weights, 2, 2, 256, 512);
177
178 assert_eq!(table.local_count(), 2);
179 assert_eq!(table.remote_count(), 2);
180 assert_eq!(table.local_token_indices, vec![0, 1]);
181 assert_eq!(table.local_expert_ids, vec![300, 256]);
182 assert_eq!(table.remote_token_indices, vec![0, 1]);
183 assert_eq!(table.remote_expert_ids, vec![10, 255]);
184 }
185
186 #[test]
187 fn test_single_token() {
188 let indices = vec![5u32, 260, 100];
189 let weights = vec![0.5f32, 0.3, 0.2];
190 let table = build_ep_routing_table(&indices, &weights, 1, 3, 0, 256);
191
192 assert_eq!(table.local_count(), 2); assert_eq!(table.remote_count(), 1); assert_eq!(table.total_count(), 3);
195 }
196
197 #[test]
198 #[should_panic(expected = "gate_indices length mismatch")]
199 fn index_length_mismatch_panics() {
200 let indices = vec![1u32, 2, 3]; let weights = vec![0.5f32; 4];
202 build_ep_routing_table(&indices, &weights, 2, 2, 0, 256);
203 }
204
205 #[test]
206 #[should_panic(expected = "gate_weights length mismatch")]
207 fn weight_length_mismatch_panics() {
208 let indices = vec![1u32, 2, 3, 4];
209 let weights = vec![0.5f32; 3];
210 build_ep_routing_table(&indices, &weights, 2, 2, 0, 256);
211 }
212}