mech_interpreter/stdlib/
vertcat.rs

1#[macro_use]
2use crate::stdlib::*;
3
4// Vertical Concatenate -----------------------------------------------------
5
6macro_rules! vertcat_one_arg {
7  ($fxn:ident, $e0:ident, $out:ident, $opt:ident) => {
8    #[derive(Debug)]
9    struct $fxn<T> {
10      e0: Ref<$e0<T>>,
11      out: Ref<$out<T>>,
12    }
13    impl<T> MechFunction for $fxn<T>
14    where
15      T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
16      Ref<$out<T>>: ToValue
17    {
18      fn solve(&self) { 
19        unsafe {
20          let e0_ptr = (*(self.e0.as_ptr())).clone();
21          let mut out_ptr = (&mut *(self.out.as_ptr()));
22          $opt!(out_ptr,e0_ptr);
23        }
24      }
25      fn out(&self) -> Value { self.out.to_value() }
26      fn to_string(&self) -> String { format!("{:#?}", self) }
27    }
28  };}
29
30macro_rules! vertcat_two_args {
31  ($fxn:ident, $e1:ident, $e2:ident, $out:ident, $opt:ident) => {
32    #[derive(Debug)]
33    struct $fxn<T> {
34      e0: Ref<$e1<T>>,
35      e1: Ref<$e2<T>>,
36      out: Ref<$out<T>>,
37    }
38    impl<T> MechFunction for $fxn<T>
39    where
40      T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
41      Ref<$out<T>>: ToValue
42    {
43      fn solve(&self) { 
44        unsafe {
45          let e0_ptr = (*(self.e0.as_ptr())).clone();
46          let e1_ptr = (*(self.e1.as_ptr())).clone();
47          let mut out_ptr = (&mut *(self.out.as_ptr()));
48          $opt!(out_ptr,e0_ptr,e1_ptr);
49        }
50      }
51      fn out(&self) -> Value { self.out.to_value() }
52      fn to_string(&self) -> String { format!("{:#?}", self) }
53    }
54  };}
55
56macro_rules! vertcat_three_args {
57  ($fxn:ident, $e0:ident, $e1:ident, $e2:ident, $out:ident, $opt:ident) => {
58    #[derive(Debug)]
59    struct $fxn<T> {
60      e0: Ref<$e0<T>>,
61      e1: Ref<$e1<T>>,
62      e2: Ref<$e2<T>>,
63      out: Ref<$out<T>>,
64    }
65    impl<T> MechFunction for $fxn<T>
66    where
67      T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
68      Ref<$out<T>>: ToValue
69    {
70      fn solve(&self) { 
71        unsafe {
72          let e0_ptr = (*(self.e0.as_ptr())).clone();
73          let e1_ptr = (*(self.e1.as_ptr())).clone();
74          let e2_ptr = (*(self.e2.as_ptr())).clone();
75          let mut out_ptr = (&mut *(self.out.as_ptr()));
76          $opt!(out_ptr,e0_ptr,e1_ptr,e2_ptr);
77        }
78      }
79      fn out(&self) -> Value { self.out.to_value() }
80      fn to_string(&self) -> String { format!("{:#?}", self) }
81    }
82  };} 
83  
84macro_rules! vertcat_four_args {
85  ($fxn:ident, $e0:ident, $e1:ident, $e2:ident, $e3:ident, $out:ident, $opt:ident) => {
86    #[derive(Debug)]
87    struct $fxn<T> {
88      e0: Ref<$e0<T>>,
89      e1: Ref<$e1<T>>,
90      e2: Ref<$e2<T>>,
91      e3: Ref<$e3<T>>,
92      out: Ref<$out<T>>,
93    }
94    impl<T> MechFunction for $fxn<T>
95    where
96      T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
97      Ref<$out<T>>: ToValue
98    {
99      fn solve(&self) { 
100        unsafe {
101          let e0_ptr = (*(self.e0.as_ptr())).clone();
102          let e1_ptr = (*(self.e1.as_ptr())).clone();
103          let e2_ptr = (*(self.e2.as_ptr())).clone();
104          let e3_ptr = (*(self.e3.as_ptr())).clone();
105          let mut out_ptr = (&mut *(self.out.as_ptr()));
106          $opt!(out_ptr,e0_ptr,e1_ptr,e2_ptr,e3_ptr);
107        }
108      }
109      fn out(&self) -> Value { self.out.to_value() }
110      fn to_string(&self) -> String { format!("{:#?}", self) }
111    }
112  };}   
113
114struct VerticalConcatenateTwoArgs<T> {
115  e0: Box<dyn CopyMat<T>>,
116  e1: Box<dyn CopyMat<T>>,
117  out: Ref<DMatrix<T>>,
118}
119impl<T> MechFunction for VerticalConcatenateTwoArgs<T>
120where
121  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
122  Ref<DMatrix<T>>: ToValue
123{
124  fn solve(&self) {
125    let offset = self.e0.copy_into_row_major(&self.out,0);
126    self.e1.copy_into_row_major(&self.out,offset);
127  }
128  fn out(&self) -> Value { self.out.to_value() }
129  fn to_string(&self) -> String { format!("VerticalConcatenateTwoArgs\n{:#?}", self.out) }
130}
131    
132struct VerticalConcatenateThreeArgs<T> {
133  e0: Box<dyn CopyMat<T>>,
134  e1: Box<dyn CopyMat<T>>,
135  e2: Box<dyn CopyMat<T>>,
136  out: Ref<DMatrix<T>>,
137}
138impl<T> MechFunction for VerticalConcatenateThreeArgs<T>
139where
140  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
141  Ref<DMatrix<T>>: ToValue
142{
143  fn solve(&self) {
144    let mut offset = self.e0.copy_into_row_major(&self.out,0);
145    offset += self.e1.copy_into_row_major(&self.out,offset);
146    self.e2.copy_into_row_major(&self.out,offset);
147  }
148  fn out(&self) -> Value { self.out.to_value() }
149  fn to_string(&self) -> String { format!("VerticalConcatenateThreeArgs\n{:#?}", self.out) }
150}
151
152struct VerticalConcatenateFourArgs<T> {
153  e0: Box<dyn CopyMat<T>>,
154  e1: Box<dyn CopyMat<T>>,
155  e2: Box<dyn CopyMat<T>>,
156  e3: Box<dyn CopyMat<T>>,
157  out: Ref<DMatrix<T>>,
158}
159impl<T> MechFunction for VerticalConcatenateFourArgs<T>
160where
161  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
162  Ref<DMatrix<T>>: ToValue
163{
164  fn solve(&self) {
165    let mut offset = self.e0.copy_into_row_major(&self.out,0);
166    offset += self.e1.copy_into_row_major(&self.out,offset);
167    offset += self.e2.copy_into_row_major(&self.out,offset);
168    self.e3.copy_into_row_major(&self.out,offset);
169
170  }
171  fn out(&self) -> Value { self.out.to_value() }
172  fn to_string(&self) -> String { format!("VerticalConcatenateFourArgs\n{:#?}", self.out) }
173}
174
175struct VerticalConcatenateNArgs<T> {
176  e0: Vec<Box<dyn CopyMat<T>>>,
177  out: Ref<DMatrix<T>>,
178}
179impl<T> MechFunction for VerticalConcatenateNArgs<T>
180where
181  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
182  Ref<DMatrix<T>>: ToValue
183{
184  fn solve(&self) {
185    let mut offset = 0;
186    for e in &self.e0 {
187      offset += e.copy_into_row_major(&self.out,offset);
188    }
189  }
190  fn out(&self) -> Value { self.out.to_value() }
191  fn to_string(&self) -> String { format!("VerticalConcatenateNArgs\n{:#?}", self.out) }
192}
193
194macro_rules! vertical_concatenate {
195  ($name:ident, $vec_size:expr) => {
196    paste!{
197      #[derive(Debug)]
198      struct $name<T> {
199        out: Ref<[<$vec_size>]<T>>,
200      }
201
202      impl<T> MechFunction for $name<T> 
203      where
204        T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
205        Ref<[<$vec_size>]<T>>: ToValue
206      {
207        fn solve(&self) {}
208        fn out(&self) -> Value { self.out.to_value() }
209        fn to_string(&self) -> String { format!("{:#?}", self) }
210      }
211    }
212  };}  
213
214struct VerticalConcatenateVD2<T> {
215  e0: Box<dyn CopyMat<T>>,
216  e1: Box<dyn CopyMat<T>>,
217  out: Ref<DVector<T>>,
218}
219
220impl<T> MechFunction for VerticalConcatenateVD2<T> 
221where
222  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
223  Ref<DVector<T>>: ToValue
224{
225  fn solve(&self) {   
226    let mut offset = self.e0.copy_into_v(&self.out,0);
227    self.e1.copy_into_v(&self.out,offset);
228  }
229  fn out(&self) -> Value { self.out.to_value() }
230  fn to_string(&self) -> String { format!("VerticalConcatenateVD2\n{:#?}", self.out) }
231}
232
233struct VerticalConcatenateVD3<T> {
234  e0: Box<dyn CopyMat<T>>,
235  e1: Box<dyn CopyMat<T>>,
236  e2: Box<dyn CopyMat<T>>,
237  out: Ref<DVector<T>>,
238}
239
240impl<T> MechFunction for VerticalConcatenateVD3<T> 
241where
242  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
243  Ref<DVector<T>>: ToValue
244{
245  fn solve(&self) {   
246    let mut offset = self.e0.copy_into_v(&self.out,0);
247    offset += self.e1.copy_into_v(&self.out,offset);
248    self.e2.copy_into_v(&self.out,offset);
249  }
250  fn out(&self) -> Value { self.out.to_value() }
251  fn to_string(&self) -> String { format!("VerticalConcatenateVD3\n{:#?}", self.out) }
252}
253
254struct VerticalConcatenateVD4<T> {
255  e0: Box<dyn CopyMat<T>>,
256  e1: Box<dyn CopyMat<T>>,
257  e2: Box<dyn CopyMat<T>>,
258  e3: Box<dyn CopyMat<T>>,
259  out: Ref<DVector<T>>,
260}
261
262impl<T> MechFunction for VerticalConcatenateVD4<T> 
263where
264  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
265  Ref<DVector<T>>: ToValue
266{
267  fn solve(&self) {   
268    let mut offset = self.e0.copy_into_v(&self.out,0);
269    offset += self.e1.copy_into_v(&self.out,offset);
270    offset += self.e2.copy_into_v(&self.out,offset);
271    self.e3.copy_into_v(&self.out,offset);
272  }
273  fn out(&self) -> Value { self.out.to_value() }
274  fn to_string(&self) -> String { format!("VerticalConcatenateVD3\n{:#?}", self.out) }
275}
276
277struct VerticalConcatenateVDN<T> {
278  scalar: Vec<(Ref<T>,usize)>,
279  matrix: Vec<(Box<dyn CopyMat<T>>,usize)>,
280  out: Ref<DVector<T>>,
281}
282
283impl<T> MechFunction for VerticalConcatenateVDN<T> 
284where
285  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
286  Ref<DVector<T>>: ToValue
287{
288  fn solve(&self) {
289    unsafe {
290      let mut out_ptr = (&mut *(self.out.as_ptr()));
291      for (e,i) in &self.matrix {
292        e.copy_into_v(&self.out,*i);
293      }
294      for (e,i) in &self.scalar {
295        out_ptr[*i] = e.borrow().clone();
296      }
297    }
298  }
299  fn out(&self) -> Value { self.out.to_value() }
300  fn to_string(&self) -> String { format!("VerticalConcatenateVDN\n{:#?}", self.out) }
301}
302
303#[derive(Debug)]
304struct VerticalConcatenateS1<T> {
305  out: Ref<Matrix1<T>>,
306}
307
308impl<T> MechFunction for VerticalConcatenateS1<T> 
309where
310  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
311  Ref<Matrix1<T>>: ToValue
312{
313  fn solve(&self) {}
314  fn out(&self) -> Value { self.out.to_value() }
315  fn to_string(&self) -> String { format!("{:#?}", self) }
316}
317
318vertical_concatenate!(VerticalConcatenateS2,Vector2);
319vertical_concatenate!(VerticalConcatenateS3,Vector3);
320vertical_concatenate!(VerticalConcatenateS4,Vector4);
321vertical_concatenate!(VerticalConcatenateV2,Vector2);
322vertical_concatenate!(VerticalConcatenateV3,Vector3);
323vertical_concatenate!(VerticalConcatenateV4,Vector4);
324vertical_concatenate!(VerticalConcatenateM2,Matrix2);
325vertical_concatenate!(VerticalConcatenateM3,Matrix3);
326vertical_concatenate!(VerticalConcatenateM2x3,Matrix2x3);
327vertical_concatenate!(VerticalConcatenateM3x2,Matrix3x2);
328vertical_concatenate!(VerticalConcatenateM4,Matrix4);
329vertical_concatenate!(VerticalConcatenateMD,DMatrix);
330vertical_concatenate!(VerticalConcatenateVD,DVector);
331
332#[derive(Debug)]
333struct VerticalConcatenateSD<T> {
334  out: Ref<DVector<T>>,
335}
336impl<T> MechFunction for VerticalConcatenateSD<T>
337where
338  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
339  Ref<DVector<T>>: ToValue
340{
341  fn solve(&self) { }
342  fn out(&self) -> Value { self.out.to_value() }
343  fn to_string(&self) -> String { format!("{:#?}", self) }
344}
345
346macro_rules! vertcat_m1m1 {
347  ($out:expr, $e0:expr, $e1:expr) => {
348    $out[0] = $e0[0].clone();
349    $out[1] = $e1[0].clone();
350  };}
351vertcat_two_args!(VerticalConcatenateM1M1,Matrix1,Matrix1,Vector2,vertcat_m1m1);
352
353macro_rules! vertcat_r2r2 {
354  ($out:expr, $e0:expr, $e1:expr) => {
355    $out[0] = $e0[0].clone();
356    $out[1] = $e0[1].clone();
357    $out[2] = $e1[0].clone();
358    $out[3] = $e1[1].clone();
359  };}
360vertcat_two_args!(VerticalConcatenateV2V2,Vector2,Vector2,Vector4,vertcat_r2r2);
361
362macro_rules! vertcat_m1r3 {
363  ($out:expr, $e0:expr, $e1:expr) => {
364    $out[0] = $e0[0].clone();
365    $out[1] = $e1[0].clone();
366    $out[2] = $e1[1].clone();
367    $out[3] = $e1[2].clone();
368  };}
369vertcat_two_args!(VerticalConcatenateM1V3,Matrix1,Vector3,Vector4,vertcat_m1r3);
370
371macro_rules! vertcat_r3m1 {
372  ($out:expr, $e0:expr, $e1:expr) => {
373    $out[0] = $e0[0].clone();
374    $out[1] = $e0[1].clone();
375    $out[2] = $e0[2].clone();
376    $out[3] = $e1[0].clone();
377  };}
378vertcat_two_args!(VerticalConcatenateV3M1,Vector3,Matrix1,Vector4,vertcat_r3m1);
379
380macro_rules! vertcat_m1r2 {
381  ($out:expr, $e0:expr, $e1:expr) => {
382    $out[0] = $e0[0].clone();
383    $out[1] = $e1[0].clone();
384    $out[2] = $e1[1].clone();
385  };
386}
387vertcat_two_args!(VerticalConcatenateM1V2, Matrix1, Vector2, Vector3, vertcat_m1r2);
388
389macro_rules! vertcat_r2m1 {
390  ($out:expr, $e0:expr, $e1:expr) => {
391    $out[0] = $e0[0].clone();
392    $out[1] = $e0[1].clone();
393    $out[2] = $e1[0].clone();
394  };
395}
396vertcat_two_args!(VerticalConcatenateV2M1, Vector2, Matrix1, Vector3, vertcat_r2m1);
397
398macro_rules! vertcat_m1m1m1 {
399  ($out:expr, $e0:expr,$e1:expr,$e2:expr) => {
400    $out[0] = $e0[0].clone();
401    $out[1] = $e1[0].clone();
402    $out[2] = $e2[0].clone();
403  };
404}
405vertcat_three_args!(VerticalConcatenateM1M1M1,Matrix1,Matrix1,Matrix1,Vector3, vertcat_m1m1m1);
406
407macro_rules! vertcat_m1m1r2 {
408  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
409    $out[0] = $e0[0].clone();
410    $out[1] = $e1[0].clone();
411    $out[2] = $e2[0].clone();
412    $out[3] = $e2[1].clone();
413  };
414}
415vertcat_three_args!(VerticalConcatenateM1M1V2, Matrix1, Matrix1, Vector2, Vector4, vertcat_m1m1r2);
416
417macro_rules! vertcat_m1r2m1 {
418  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
419    $out[0] = $e0[0].clone();
420    $out[1] = $e1[0].clone();
421    $out[2] = $e1[1].clone();
422    $out[3] = $e2[0].clone();
423  };
424}
425vertcat_three_args!(VerticalConcatenateM1V2M1, Matrix1, Vector2, Matrix1, Vector4, vertcat_m1r2m1);
426
427macro_rules! vertcat_r2m1m1 {
428  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
429    $out[0] = $e0[0].clone();
430    $out[1] = $e0[1].clone();
431    $out[2] = $e1[0].clone();
432    $out[3] = $e2[0].clone();
433  };
434}
435vertcat_three_args!(VerticalConcatenateV2M1M1, Vector2, Matrix1, Matrix1, Vector4, vertcat_r2m1m1);
436
437#[derive(Debug)]
438struct VerticalConcatenateM1M1M1M1<T> {
439  e0: Ref<Matrix1<T>>,
440  e1: Ref<Matrix1<T>>,
441  e2: Ref<Matrix1<T>>,
442  e3: Ref<Matrix1<T>>,
443  out: Ref<Vector4<T>>,
444}
445impl<T> MechFunction for VerticalConcatenateM1M1M1M1<T>
446where
447  T: Copy + Debug + Clone + Sync + Send + PartialEq + 'static,
448  Ref<Vector4<T>>: ToValue
449{
450  fn solve(&self) { 
451    unsafe {
452      let e0_ptr = (*(self.e0.as_ptr())).clone();
453      let e1_ptr = (*(self.e1.as_ptr())).clone();
454      let e2_ptr = (*(self.e2.as_ptr())).clone();
455      let e3_ptr = (*(self.e3.as_ptr())).clone();
456      let mut out_ptr = (&mut *(self.out.as_ptr()));
457      out_ptr[0] = e0_ptr[0].clone();
458      out_ptr[1] = e1_ptr[0].clone();
459      out_ptr[2] = e2_ptr[0].clone();
460      out_ptr[3] = e3_ptr[0].clone();
461    }
462  }
463  fn out(&self) -> Value { self.out.to_value() }
464  fn to_string(&self) -> String { format!("{:#?}", self) }
465}
466
467macro_rules! vertcat_r2r2 {
468  ($out:expr, $e0:expr, $e1:expr) => {
469    $out[0] = $e0[0].clone();
470    $out[2] = $e0[1].clone();
471    $out[1] = $e1[0].clone();
472    $out[3] = $e1[1].clone();
473  };
474}
475vertcat_two_args!(VerticalConcatenateR2R2, RowVector2, RowVector2, Matrix2, vertcat_r2r2);
476
477macro_rules! vertcat_r3r3 {
478  ($out:expr, $e0:expr, $e1:expr) => {
479    $out[0] = $e0[0].clone();
480    $out[2] = $e0[1].clone();
481    $out[4] = $e0[2].clone();
482    $out[1] = $e1[0].clone();
483    $out[3] = $e1[1].clone();
484    $out[5] = $e1[2].clone();
485  };
486}
487vertcat_two_args!(VerticalConcatenateR3R3, RowVector3, RowVector3, Matrix2x3, vertcat_r3r3);
488
489macro_rules! vertcat_r2m2 {
490  ($out:expr, $e0:expr, $e1:expr) => {
491    $out[0] = $e0[0].clone();
492    $out[3] = $e0[1].clone();
493    $out[1] = $e1[0].clone();
494    $out[2] = $e1[1].clone();
495    $out[4] = $e1[2].clone();
496    $out[5] = $e1[3].clone();
497  };
498}
499vertcat_two_args!(VerticalConcatenateR2M2, RowVector2, Matrix2, Matrix3x2, vertcat_r2m2);
500
501macro_rules! vertcat_m2r2 {
502  ($out:expr, $e0:expr, $e1:expr) => {
503    $out[0] = $e0[0].clone();
504    $out[1] = $e0[1].clone();
505    $out[3] = $e0[2].clone();
506    $out[4] = $e0[3].clone();
507    $out[2] = $e1[0].clone();
508    $out[5] = $e1[1].clone();
509  };
510}
511vertcat_two_args!(VerticalConcatenateM2R2, Matrix2, RowVector2, Matrix3x2, vertcat_m2r2);
512
513macro_rules! vertcat_m2x3r3 {
514  ($out:expr, $e0:expr, $e1:expr) => {
515    $out[0] = $e0[0].clone();
516    $out[1] = $e0[1].clone();
517    $out[3] = $e0[2].clone();
518    $out[4] = $e0[3].clone();
519    $out[6] = $e0[4].clone();
520    $out[7] = $e0[5].clone();
521    $out[2] = $e1[0].clone();
522    $out[5] = $e1[1].clone();
523    $out[8] = $e1[2].clone();
524  };
525}
526vertcat_two_args!(VerticalConcatenateM2x3R3, Matrix2x3, RowVector3, Matrix3, vertcat_m2x3r3);
527
528macro_rules! vertcat_r3m2x3 {
529  ($out:expr, $e0:expr, $e1:expr) => {
530    $out[0] = $e0[0].clone();
531    $out[3] = $e0[1].clone();
532    $out[6] = $e0[2].clone();
533    $out[1] = $e1[0].clone();
534    $out[2] = $e1[1].clone();
535    $out[4] = $e1[2].clone();
536    $out[5] = $e1[3].clone();
537    $out[7] = $e1[4].clone();
538    $out[8] = $e1[5].clone();
539  };
540}
541vertcat_two_args!(VerticalConcatenateR3M2x3, RowVector3, Matrix2x3, Matrix3, vertcat_r3m2x3);
542
543
544macro_rules! vertcat_mdv4 {
545  ($out:expr, $e0:expr, $e1:expr) => {
546    let e0_len = $e0.len();
547    for i in 0..e0_len {
548      $out[i] = $e0[i].clone();
549    }
550    let offset = e0_len;
551    $out[offset] = $e1[0].clone();
552    $out[offset + 1] = $e1[1].clone();
553    $out[offset + 2] = $e1[2].clone();
554    $out[offset + 3] = $e1[3].clone();
555  };
556}
557vertcat_two_args!(VerticalConcatenateMDR4, DMatrix, RowVector4, Matrix4, vertcat_mdv4);
558
559macro_rules! vertcat_mdmd {
560  ($out:expr, $e0:expr, $e1:expr) => {
561    let dest_rows = $out.nrows();
562    let mut offset = 0;
563    let mut dest_ix = 0;
564
565    let src_rows = $e0.nrows();
566    let stride = dest_rows - src_rows;
567    dest_ix = offset;
568    for ix in 0..$e0.len() {
569      $out[dest_ix] = $e0[ix].clone();
570      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
571    }
572    offset += src_rows;
573
574    let src_rows = $e1.nrows();
575    let stride = dest_rows - src_rows;
576    dest_ix = offset;
577    for ix in 0..$e1.len() {
578      $out[dest_ix] = $e1[ix].clone();
579      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
580    }
581  };
582}
583vertcat_two_args!(VerticalConcatenateMDMD, DMatrix, DMatrix, Matrix4, vertcat_mdmd);
584vertcat_two_args!(VerticalConcatenateR4MD, RowVector4, DMatrix, Matrix4, vertcat_mdmd);
585
586
587macro_rules! vertcat_mdmdmd {
588  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
589    let dest_rows = $out.nrows();
590    let mut offset = 0;
591    let mut dest_ix = 0;
592
593    let src_rows = $e0.nrows();
594    let stride = dest_rows - src_rows;
595    dest_ix = offset;
596    for ix in 0..$e0.len() {
597      $out[dest_ix] = $e0[ix].clone();
598      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
599    }
600    offset += src_rows;
601
602    let src_rows = $e1.nrows();
603    let stride = dest_rows - src_rows;
604    dest_ix = offset;
605    for ix in 0..$e1.len() {
606      $out[dest_ix] = $e1[ix].clone();
607      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
608    }
609    offset += src_rows;
610
611    let src_rows = $e2.nrows();
612    let stride = dest_rows - src_rows;
613    dest_ix = offset;
614    for ix in 0..$e2.len() {
615      $out[dest_ix] = $e2[ix].clone();
616      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
617    }
618  };
619}
620
621vertcat_three_args!(VerticalConcatenateR2R2R2, RowVector2, RowVector2, RowVector2, Matrix3x2, vertcat_mdmdmd);
622vertcat_three_args!(VerticalConcatenateR3R3R3, RowVector3, RowVector3, RowVector3, Matrix3, vertcat_mdmdmd);
623vertcat_three_args!(VerticalConcatenateR4R4MD, RowVector4, RowVector4, DMatrix, Matrix4, vertcat_mdmdmd);
624vertcat_three_args!(VerticalConcatenateR4MDR4, RowVector4, DMatrix, RowVector4, Matrix4, vertcat_mdmdmd);
625vertcat_three_args!(VerticalConcatenateMDR4R4, DMatrix, RowVector4, RowVector4, Matrix4, vertcat_mdmdmd);
626
627macro_rules! vertcat_mdmdmdmd {
628  ($out:expr, $e0:expr, $e1:expr, $e2:expr, $e3:expr) => {
629    let dest_rows = $out.nrows();
630    let mut offset = 0;
631    let mut dest_ix = 0;
632
633    let src_rows = $e0.nrows();
634    let stride = dest_rows - src_rows;
635    dest_ix = offset;
636    for ix in 0..$e0.len() {
637      $out[dest_ix] = $e0[ix].clone();
638      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
639    }
640    offset += src_rows;
641
642    let src_rows = $e1.nrows();
643    let stride = dest_rows - src_rows;
644    dest_ix = offset;
645    for ix in 0..$e1.len() {
646      $out[dest_ix] = $e1[ix].clone();
647      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
648    }
649    offset += src_rows;
650
651    let src_rows = $e2.nrows();
652    let stride = dest_rows - src_rows;
653    dest_ix = offset;
654    for ix in 0..$e2.len() {
655      $out[dest_ix] = $e2[ix].clone();
656      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
657    }
658    offset += src_rows;
659
660    let src_rows = $e3.nrows();
661    let stride = dest_rows - src_rows;
662    dest_ix = offset;
663    for ix in 0..$e3.len() {
664      $out[dest_ix] = $e3[ix].clone();
665      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
666    }
667  };
668}
669
670vertcat_four_args!(VerticalConcatenateR4R4R4R4, RowVector4, RowVector4, RowVector4, RowVector4, Matrix4, vertcat_mdmdmdmd);
671
672macro_rules! impl_vertcat_arms {
673  ($kind:ident, $args:expr, $default:expr) => {
674    paste!{
675    {
676      let arguments = $args;  
677      let rows = arguments[0].shape()[0];
678      let rows:usize = arguments.iter().fold(0, |acc, x| acc + x.shape()[0]);
679      let columns:usize = arguments[0].shape()[1];
680      let nargs = arguments.len();
681      let kinds: Vec<ValueKind> = arguments.iter().map(|x| x.kind()).collect::<Vec<ValueKind>>();
682      let no_refs = !kinds.iter().any(|x| {
683        match x {
684          ValueKind::Reference(_) => true,
685          ValueKind::Matrix(_,_) => true,
686          _ => false,
687      }});
688      if no_refs {
689        let mat: Vec<$kind> = arguments.iter().flat_map(|v| v.[<as_vec $kind:lower>]().unwrap()).collect::<Vec<$kind>>();
690        fn to_column_major<T: Clone>(out: &[Value], row_n: usize, col_n: usize, extract_fn: impl Fn(&Value) -> Option<Vec<T>> + Clone) -> Vec<T> {
691          (0..col_n).flat_map(|col| out.iter().map({let value = extract_fn.clone();move |row| value(row).unwrap()[col].clone()})).collect()
692        }
693        let mat = to_column_major(&arguments, rows, columns, |v| v.[<as_vec $kind:lower>]());
694        match (rows,columns) {
695          (2,1) => {return Ok(Box::new(VerticalConcatenateS2{out:new_ref(Vector2::from_vec(mat))}));}
696          (3,1) => {return Ok(Box::new(VerticalConcatenateS3{out:new_ref(Vector3::from_vec(mat))}));}
697          (4,1) => {return Ok(Box::new(VerticalConcatenateS4{out:new_ref(Vector4::from_vec(mat))}));}
698          (m,1) => {return Ok(Box::new(VerticalConcatenateSD{out:new_ref(DVector::from_vec(mat))}));}
699          (2,2) => {return Ok(Box::new(VerticalConcatenateM2{out:new_ref(Matrix2::from_vec(mat))}));}
700          (3,3) => {return Ok(Box::new(VerticalConcatenateM3{out:new_ref(Matrix3::from_vec(mat))}));}
701          (4,4) => {return Ok(Box::new(VerticalConcatenateM4{out:new_ref(Matrix4::from_vec(mat))}));}
702          (2,3) => {return Ok(Box::new(VerticalConcatenateM2x3{out:new_ref(Matrix2x3::from_vec(mat))}));}
703          (3,2) => {return Ok(Box::new(VerticalConcatenateM3x2{out:new_ref(Matrix3x2::from_vec(mat))}));}
704          (m,n) => {return Ok(Box::new(VerticalConcatenateMD{out:new_ref(DMatrix::from_vec(m,n,mat))}));}
705        }
706      } else {
707        match (nargs,rows,columns) {
708          #[cfg(feature = "Vector2")]
709          (1,2,1) => {
710            match &arguments[..] {
711              // r2
712              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0))] => {
713                return Ok(Box::new(VerticalConcatenateV2{out: e0.clone()}));
714              }
715              _ => todo!(),
716            }
717          }
718          #[cfg(feature = "Vector3")]
719          (1,3,1) => {
720            match &arguments[..] {
721              // r3
722              [Value::MutableReference(e0)] => {
723                match *e0.borrow() {
724                  Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e0)) => {
725                    return Ok(Box::new(VerticalConcatenateV3{out: e0.clone()}));
726                  }
727                  _ => todo!(),
728                }
729              }
730              _ => todo!(),
731            }
732          }
733          #[cfg(feature = "Vector4")]
734          (1,4,1) => {
735            match &arguments[..] {
736              // r4
737              [Value::[<Matrix $kind:camel>](Matrix::Vector4(ref e0))] => {
738                return Ok(Box::new(VerticalConcatenateV4{out: e0.clone()}));
739              }
740              _ => todo!(),
741            }
742          }
743          #[cfg(feature = "VectorD")]
744          (1,m,1) => {
745            match &arguments[..] {
746              // rd
747              [Value::[<Matrix $kind:camel>](Matrix::DVector(ref e0))] => {
748                return Ok(Box::new(VerticalConcatenateVD{out: e0.clone()}));
749              }
750              _ => todo!(),
751            }
752          }
753          #[cfg(feature = "Vector2")]
754          (2,2,1) => {
755            let mut out = Vector2::from_element($default);
756            match &arguments[..] {
757              // m1m1
758              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
759                return Ok(Box::new(VerticalConcatenateM1M1{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
760              }
761              _ => todo!(),
762            }
763          }
764          #[cfg(feature = "Vector3")]
765          (2,3,1) => {
766            let mut out = Vector3::from_element($default);
767            match &arguments[..] {
768              //m1v2
769              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1))] => {
770                return Ok(Box::new(VerticalConcatenateM1V2{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
771              }
772              //v2m1
773              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
774                return Ok(Box::new(VerticalConcatenateV2M1{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
775              }
776              _ => todo!(),
777            }
778          }
779          #[cfg(feature = "Vector4")]
780          (2,4,1) => {
781            let mut out = Vector4::from_element($default);
782            match &arguments[..] {
783              // m1v3
784              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e1))] => {
785                return Ok(Box::new(VerticalConcatenateM1V3{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
786              }
787              // v3m1
788              [Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
789                return Ok(Box::new(VerticalConcatenateV3M1{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
790              }
791              // v2v2
792              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1))] => {
793                return Ok(Box::new(VerticalConcatenateV2V2{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
794              }              
795              _ => todo!(),
796            }
797          } 
798          #[cfg(feature = "VectorD")]
799          (2,m,1) => {
800            let mut out = DVector::from_element(m,$default);
801            match &arguments[..] {
802              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1)] => {
803                let e0 = e0.get_copyable_matrix();
804                let e1 = e1.get_copyable_matrix();
805                return Ok(Box::new(VerticalConcatenateVD2{e0, e1, out: new_ref(out)}));
806              }
807              _ => todo!(),
808            }
809          }
810          #[cfg(feature = "Vector3")]
811          (3,3,1) => {  
812            let mut out = Vector3::from_element($default);
813            match &arguments[..] {
814              // m1 m1 m1
815              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
816                return Ok(Box::new(VerticalConcatenateM1M1M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: new_ref(out)}));
817              }    
818              _ => todo!()
819            }
820          }
821          #[cfg(feature = "Vector4")]
822          (3,4,1) => {
823            let mut out = Vector4::from_element($default);
824            match &arguments[..] {
825              // m1 m1 r2
826              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e2))] => {
827                return Ok(Box::new(VerticalConcatenateM1M1V2{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: new_ref(out)}));
828              }
829              // m1 r2 m1
830              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
831                return Ok(Box::new(VerticalConcatenateM1V2M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: new_ref(out)}));
832              }
833              // r2 m1 m1
834              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
835                return Ok(Box::new(VerticalConcatenateV2M1M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: new_ref(out)}));
836              }
837              _ => todo!()
838            }
839          }
840          #[cfg(feature = "VectorD")]
841          (3,m,1) => {
842            let mut out = DVector::from_element(m,$default);
843            match &arguments[..] {
844              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1),Value::[<Matrix $kind:camel>](e2)] => {
845                let e0 = e0.get_copyable_matrix();
846                let e1 = e1.get_copyable_matrix();
847                let e2 = e2.get_copyable_matrix();
848                return Ok(Box::new(VerticalConcatenateVD3{e0, e1, e2, out: new_ref(out)}));
849              }
850              _ => todo!(),
851            }
852          }
853          #[cfg(feature = "Vector4")]
854          (4,4,1) => {
855            let mut out = Vector4::from_element($default);
856            match &arguments[..] {
857              // m1 m1 m1 m1
858              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e3))] => {
859                return Ok(Box::new(VerticalConcatenateM1M1M1M1{ e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), e3: e3.clone(), out: new_ref(out) }));
860              }
861              _ => todo!(),
862            }
863          }
864          #[cfg(feature = "VectorD")]
865          (4,m,1) => {
866            let mut out = DVector::from_element(m,$default);
867            match &arguments[..] {
868              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1),Value::[<Matrix $kind:camel>](e2),Value::[<Matrix $kind:camel>](e3)] => {
869                let e0 = e0.get_copyable_matrix();
870                let e1 = e1.get_copyable_matrix();
871                let e2 = e2.get_copyable_matrix();
872                let e3 = e3.get_copyable_matrix();
873                return Ok(Box::new(VerticalConcatenateVD4{e0, e1, e2, e3, out: new_ref(out)}));
874              }
875              _ => todo!(),
876            }
877          }
878          #[cfg(feature = "VectorD")]
879          (l,m,1) => {
880            let mut out = DVector::from_element(m,$default);
881            let mut matrix_args: Vec<(Box<dyn CopyMat<$kind>>,usize)> = vec![];
882            let mut scalar_args: Vec<(Ref<$kind>,usize)> = vec![];
883            let mut i = 0;
884            for arg in arguments.iter() {
885              match &arg {
886                Value::[<$kind:camel>](e0) => {
887                  scalar_args.push((e0.clone(),i));
888                  i += 1;
889                }
890                Value::[<Matrix $kind:camel>](e0) => {
891                  matrix_args.push((e0.get_copyable_matrix(),i));
892                  i += e0.shape()[0];
893                }
894                _ => todo!(),
895              }
896            }
897            return Ok(Box::new(VerticalConcatenateVDN{scalar: scalar_args, matrix: matrix_args, out: new_ref(out)}));
898          }
899          #[cfg(feature = "Matrix2")]
900          (2,2,2) => {
901            let mut out = Matrix2::from_element($default);
902            match &arguments[..] {
903              // v2v2
904              [Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e1))] => {return Ok(Box::new(VerticalConcatenateR2R2{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));}
905              _ => todo!(),
906            }
907          }
908          #[cfg(feature = "Matrix2x3")]
909          (2,2,3) => {
910            let mut out = Matrix2x3::from_element($default);
911            match &arguments[..] {
912              // r3r3
913              [Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e1))] => {return Ok(Box::new(VerticalConcatenateR3R3{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));}
914              _ => todo!(),
915            }
916          }
917          #[cfg(feature = "Matrix3x2")]
918          (2,3,2) => {
919            let mut out = Matrix3x2::from_element($default);
920            match &arguments[..] {
921              // v2m2
922              [Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix2(ref e1))] => {
923                return Ok(Box::new(VerticalConcatenateR2M2{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
924              }
925              // m2v2
926              [Value::[<Matrix $kind:camel>](Matrix::Matrix2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e1))] => {
927                return Ok(Box::new(VerticalConcatenateM2R2{e0: e0.clone(), e1: e1.clone(), out: new_ref(out)}));
928              }
929              _ => todo!(),
930            }
931            
932          }
933          #[cfg(feature = "Matrix3")]
934          (2,3,3) => {
935            let mut out = Matrix3::from_element($default);
936            match &arguments[..] {
937              // v3m3x2
938              [Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix2x3(ref e1))] => {
939                return Ok(Box::new(VerticalConcatenateR3M2x3 { e0: e0.clone(), e1: e1.clone(), out: new_ref(out) }));
940              }
941              // m3x2v3
942              [Value::[<Matrix $kind:camel>](Matrix::Matrix2x3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e1))] => {
943                return Ok(Box::new(VerticalConcatenateM2x3R3 { e0: e0.clone(), e1: e1.clone(), out: new_ref(out) }));
944              }
945              _ => todo!(),
946            }
947            
948          }
949          #[cfg(feature = "Matrix4")]
950          (2,4,4) => {
951            let mut out = Matrix4::from_element($default);
952            match &arguments[..] {
953              // v4md
954              [Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e0)), Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e1))] => Ok(Box::new(VerticalConcatenateR4MD{e0:e0.clone(),e1:e1.clone(),out:new_ref(out)})),
955              // mdv4
956              [Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e0)), Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e1))] => Ok(Box::new(VerticalConcatenateMDR4{e0:e0.clone(),e1:e1.clone(),out:new_ref(out)})),
957              // mdmd
958              [Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e0)), Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e1))] => Ok(Box::new(VerticalConcatenateMDMD{e0:e0.clone(),e1:e1.clone(),out:new_ref(out)})),
959              _ => todo!(),
960            }
961            
962          }
963          #[cfg(feature = "MatrixD")]
964          (2,m,n) => {
965            let mut out = DMatrix::from_element(m,n,$default);
966            match &arguments[..] {
967              [Value::[<Matrix $kind:camel>](m0), Value::[<Matrix $kind:camel>](m1)] => {
968                let e0 = m0.get_copyable_matrix();
969                let e1 = m1.get_copyable_matrix();
970                Ok(Box::new(VerticalConcatenateTwoArgs{e0, e1, out: new_ref(out)}))
971              }
972              _ => todo!(),
973            }            
974          }
975          #[cfg(feature = "Matrix3x2")]
976          (3,3,2) => {
977            let mut out = Matrix3x2::from_element($default);
978            match &arguments[..] {
979              // r2r2r2
980              [Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e1)),Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e2))]=>Ok(Box::new(VerticalConcatenateR2R2R2{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),out:new_ref(out)})),
981              _ => todo!(),
982            }
983          }
984          #[cfg(feature = "Matrix3")]
985          (3,3,3) => {
986            let mut out = Matrix3::from_element($default);
987            match &arguments[..] {
988              // v3v3v3
989              [Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e1)),Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e2))]=>Ok(Box::new(VerticalConcatenateR3R3R3{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),out:new_ref(out)})),
990              _ => todo!(),
991            }
992          }
993          #[cfg(feature = "Matrix4")]
994          (3,4,4) => {
995            let mut out = Matrix4::from_element($default);
996            match &arguments[..] {
997               // v4v4md
998              [Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e1)),Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e2))]=>Ok(Box::new(VerticalConcatenateR4R4MD{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),out:new_ref(out)})),
999              // v4mdv4
1000              [Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e0)),Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e1)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e2))]=>Ok(Box::new(VerticalConcatenateR4MDR4{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),out:new_ref(out)})),
1001              // mdv4v4
1002              [Value::[<Matrix $kind:camel>](Matrix::DMatrix(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e1)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e2))]=>Ok(Box::new(VerticalConcatenateMDR4R4{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),out:new_ref(out)})),
1003              _ => todo!(),
1004            }
1005          }
1006          #[cfg(feature = "MatrixD")]
1007          (3,m,n) => {
1008            let mut out = DMatrix::from_element(m,n,$default);
1009            match &arguments[..] {
1010              [Value::[<Matrix $kind:camel>](m0),Value::[<Matrix $kind:camel>](m1),Value::[<Matrix $kind:camel>](m2)] => {
1011                let e0 = m0.get_copyable_matrix();
1012                let e1 = m1.get_copyable_matrix();
1013                let e2 = m2.get_copyable_matrix();
1014                Ok(Box::new(VerticalConcatenateThreeArgs{e0,e1,e2,out:new_ref(out)}))
1015              }   
1016              _ => todo!(),
1017            }
1018          }
1019          #[cfg(feature = "Matrix4")]
1020          (4,4,4) => {
1021            let mut out = Matrix4::from_element($default);
1022            match &arguments[..] {
1023              // v4v4v4v4
1024              [Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e0)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e1)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e2)),Value::[<Matrix $kind:camel>](Matrix::RowVector4(ref e3))]=>Ok(Box::new(VerticalConcatenateR4R4R4R4{e0:e0.clone(),e1:e1.clone(),e2:e2.clone(),e3:e3.clone(),out:new_ref(out)})),
1025              _ => todo!(),
1026            }
1027          }
1028          #[cfg(feature = "MatrixD")]
1029          (4,m,n) => {
1030            let mut out = DMatrix::from_element(m,n,$default);
1031            match &arguments[..] {
1032              [Value::[<Matrix $kind:camel>](m0),Value::[<Matrix $kind:camel>](m1),Value::[<Matrix $kind:camel>](m2),Value::[<Matrix $kind:camel>](m3)] => {
1033                let e0 = m0.get_copyable_matrix();
1034                let e1 = m1.get_copyable_matrix();
1035                let e2 = m2.get_copyable_matrix();
1036                let e3 = m3.get_copyable_matrix();
1037                Ok(Box::new(VerticalConcatenateFourArgs{e0,e1,e2,e3,out:new_ref(out)}))
1038              }   
1039              _ => todo!(),
1040            }
1041          }
1042          #[cfg(feature = "MatrixD")]
1043          (l,m,n) => {
1044            let mut out = DMatrix::from_element(m,n,$default);
1045            let mut args = vec![];
1046            for arg in arguments {
1047              match arg {
1048                Value::[<Matrix $kind:camel>](m0) => {
1049                  let e0 = m0.get_copyable_matrix();
1050                  args.push(e0);
1051                }
1052                _ => todo!(),
1053              }
1054            }
1055            Ok(Box::new(VerticalConcatenateNArgs{e0: args, out:new_ref(out)}))
1056          }
1057          _ => {return Err(MechError{file: file!().to_string(), tokens: vec![], msg: "".to_string(), id: line!(), kind: MechErrorKind::UnhandledFunctionArgumentKind});}
1058        }
1059  }}}}}
1060
1061fn impl_vertcat_fxn(arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
1062  // are they all the same?
1063  //let same = kinds.iter().all(|x| *x == target_kind);
1064  let kinds: Vec<ValueKind> = arguments.iter().map(|x| x.kind()).collect::<Vec<ValueKind>>();
1065  let target_kind = kinds[0].clone();
1066  if ValueKind::is_compatible(target_kind.clone(), ValueKind::F64)  { impl_vertcat_arms!(F64,arguments,F64::zero())
1067  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::F32)  { impl_vertcat_arms!(F32,arguments,F32::zero())
1068  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::U8)  { impl_vertcat_arms!(u8,arguments,u8::zero())    
1069  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::U16)  { impl_vertcat_arms!(u16,arguments,u16::zero())    
1070  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::U32)  { impl_vertcat_arms!(u32,arguments,u32::zero())    
1071  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::U64)  { impl_vertcat_arms!(u64,arguments,u64::zero())    
1072  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::U128)  { impl_vertcat_arms!(u128,arguments,u128::zero())    
1073  } else if ValueKind::is_compatible(target_kind.clone(), ValueKind::Bool)  { impl_vertcat_arms!(bool,arguments,false)
1074  } else {
1075    todo!();
1076  }
1077}
1078
1079pub struct MaxtrixVertCat {}
1080impl NativeFunctionCompiler for MaxtrixVertCat {
1081  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
1082    // First, get the size of the output matrix
1083    // rows are consistent already so we can just get nrows from the first element
1084    impl_vertcat_fxn(arguments)
1085  }
1086}