mech_interpreter/stdlib/
vertcat.rs

1#[macro_use]
2use crate::stdlib::*;
3
4macro_rules! register_vertical_concatenate_fxn {
5  ($name:ident) => {
6    register_fxn_descriptor!(
7      $name, 
8      bool, "bool", 
9      String, "string", 
10      u8, "u8", 
11      u16, "u16", 
12      u32, "u32", 
13      u64, "u64", 
14      u128, "u128", 
15      i8, "i8", 
16      i16, "i16", 
17      i32, "i32", 
18      i64, "i64", 
19      i128, "i128", 
20      f32, "f32", 
21      f64, "f64", 
22      C64, "c64", 
23      R64, "r64"
24    );
25  };
26}
27
28macro_rules! register_fxns {
29  ($op:ident) => {
30    $op!(bool, "bool");
31    $op!(String, "string");
32    $op!(u8, "u8");
33    $op!(u16, "u16");
34    $op!(u32, "u32");
35    $op!(u64, "u64");
36    $op!(u128, "u128");
37    $op!(i8, "i8");
38    $op!(i16, "i16");
39    $op!(i32, "i32");
40    $op!(i64, "i64");
41    $op!(i128, "i128");
42    $op!(f64, "f64");
43    $op!(f32, "f32");
44    $op!(R64, "r64");
45    $op!(C64, "c64");
46  }
47}
48
49
50// Vertical Concatenate -----------------------------------------------------
51
52macro_rules! vertcat_two_args {
53  ($fxn:ident, $e0:ident, $e1:ident, $out:ident, $opt:ident) => {
54    #[derive(Debug)]
55    struct $fxn<T> {
56      e0: Ref<$e0<T>>,
57      e1: Ref<$e1<T>>,
58      out: Ref<$out<T>>,
59    }
60    impl<T> MechFunctionFactory for $fxn<T>
61    where
62      T: Debug + Clone + Sync + Send + PartialEq + 'static +
63      ConstElem + CompileConst + AsValueKind,
64      Ref<$out<T>>: ToValue
65    {
66      fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
67        match args {
68          FunctionArgs::Binary(out, arg0, arg1) => {
69            let e0: Ref<$e0<T>> = unsafe { arg0.as_unchecked() }.clone();
70            let e1: Ref<$e1<T>> = unsafe { arg1.as_unchecked() }.clone();
71            let out: Ref<$out<T>> = unsafe { out.as_unchecked() }.clone();
72            Ok(Box::new(Self { e0, e1, out }))
73          },
74          _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 2, found: args.len()}, None).with_compiler_loc())
75        }
76      }
77    }
78    impl<T> MechFunctionImpl for $fxn<T>
79    where
80      T: Debug + Clone + Sync + Send + PartialEq + 'static,
81      Ref<$out<T>>: ToValue
82    {
83      fn solve(&self) { 
84        unsafe {
85          let e0_ptr = (*(self.e0.as_ptr())).clone();
86          let e1_ptr = (*(self.e1.as_ptr())).clone();
87          let mut out_ptr = (&mut *(self.out.as_mut_ptr()));
88          $opt!(out_ptr, e0_ptr, e1_ptr);
89        }
90      }
91      fn out(&self) -> Value { self.out.to_value() }
92      fn to_string(&self) -> String { format!("{:#?}", self) }
93    }
94    #[cfg(feature = "compiler")]
95    impl<T> MechFunctionCompiler for $fxn<T> 
96    where
97      T: ConstElem + CompileConst + AsValueKind
98    {
99      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
100        let name = format!("{}<{}{}{}{}>", stringify!($fxn), T::as_value_kind(), stringify!($out), stringify!($e0), stringify!($e1));
101        compile_binop!(name, self.out, self.e0, self.e1, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
102      }
103    }
104    macro_rules! register_vertcat_fxn {
105      ($type:ty, $type_string:tt) => {
106        paste!{ 
107          #[cfg(feature = $type_string)]
108          register_descriptor! {
109            FunctionDescriptor {
110            name: concat!(stringify!($fxn), "<", stringify!([<$type:lower>]), stringify!($out), stringify!($e0), stringify!($e1), ">"),
111            ptr: $fxn::<$type>::new,
112            }
113          }
114        }
115      };
116    }
117    register_fxns!(register_vertcat_fxn);
118  };
119}
120
121macro_rules! vertcat_three_args {
122  ($fxn:ident, $e0:ident, $e1:ident, $e2:ident, $out:ident, $opt:ident) => {
123    #[derive(Debug)]
124    struct $fxn<T> {
125      e0: Ref<$e0<T>>,
126      e1: Ref<$e1<T>>,
127      e2: Ref<$e2<T>>,
128      out: Ref<$out<T>>,
129    }
130    impl<T> MechFunctionFactory for $fxn<T>
131    where
132      T: Debug + Clone + Sync + Send + PartialEq + 'static +
133      ConstElem + CompileConst + AsValueKind,
134      Ref<$out<T>>: ToValue
135    {
136      fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
137        match args {
138          FunctionArgs::Ternary(out, arg0, arg1, arg2) => {
139            let e0: Ref<$e0<T>> = unsafe { arg0.as_unchecked() }.clone();
140            let e1: Ref<$e1<T>> = unsafe { arg1.as_unchecked() }.clone();
141            let e2: Ref<$e2<T>> = unsafe { arg2.as_unchecked() }.clone();
142            let out: Ref<$out<T>> = unsafe { out.as_unchecked() }.clone();
143            Ok(Box::new(Self { e0, e1, e2, out }))
144          },
145          _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 3, found: args.len()}, None).with_compiler_loc())
146        }
147      }
148    }
149    impl<T> MechFunctionImpl for $fxn<T>
150    where
151      T: Debug + Clone + Sync + Send + PartialEq + 'static,
152      Ref<$out<T>>: ToValue
153    {
154      fn solve(&self) { 
155        unsafe {
156          let e0_ptr = (*(self.e0.as_ptr())).clone();
157          let e1_ptr = (*(self.e1.as_ptr())).clone();
158          let e2_ptr = (*(self.e2.as_ptr())).clone();
159          let mut out_ptr = (&mut *(self.out.as_mut_ptr()));
160          $opt!(out_ptr,e0_ptr,e1_ptr,e2_ptr);
161        }
162      }
163      fn out(&self) -> Value { self.out.to_value() }
164      fn to_string(&self) -> String { format!("{:#?}", self) }
165    }
166    #[cfg(feature = "compiler")]
167    impl<T> MechFunctionCompiler for $fxn<T> 
168    where
169      T: ConstElem + CompileConst + AsValueKind + AsValueKind
170    {
171      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
172        let name = format!("{}<{}>", stringify!($fxn), T::as_value_kind());
173        compile_ternop!(name, self.out, self.e0, self.e1, self.e2, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
174      }
175    }
176    register_vertical_concatenate_fxn!($fxn);
177  };} 
178  
179macro_rules! vertcat_four_args {
180  ($fxn:ident, $e0:ident, $e1:ident, $e2:ident, $e3:ident, $out:ident, $opt:ident) => {
181    #[derive(Debug)]
182    struct $fxn<T> {
183      e0: Ref<$e0<T>>,
184      e1: Ref<$e1<T>>,
185      e2: Ref<$e2<T>>,
186      e3: Ref<$e3<T>>,
187      out: Ref<$out<T>>,
188    }
189    impl<T> MechFunctionFactory for $fxn<T>
190    where
191      T: Debug + Clone + Sync + Send + PartialEq + 'static +
192      ConstElem + CompileConst + AsValueKind,
193      Ref<$out<T>>: ToValue
194    {
195      fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
196        match args {
197          FunctionArgs::Quaternary(out, arg0, arg1, arg2, arg3) => {
198            let e0: Ref<$e0<T>> = unsafe { arg0.as_unchecked() }.clone();
199            let e1: Ref<$e1<T>> = unsafe { arg1.as_unchecked() }.clone();
200            let e2: Ref<$e2<T>> = unsafe { arg2.as_unchecked() }.clone();
201            let e3: Ref<$e3<T>> = unsafe { arg3.as_unchecked() }.clone();
202            let out: Ref<$out<T>> = unsafe { out.as_unchecked() }.clone();
203            Ok(Box::new(Self { e0, e1, e2, e3, out }))
204          },
205          _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 4, found: args.len()}, None).with_compiler_loc())
206        }
207      }
208    }
209    impl<T> MechFunctionImpl for $fxn<T>
210    where
211      T: Debug + Clone + Sync + Send + PartialEq + 'static,
212      Ref<$out<T>>: ToValue
213    {
214      fn solve(&self) { 
215        unsafe {
216          let e0_ptr = (*(self.e0.as_ptr())).clone();
217          let e1_ptr = (*(self.e1.as_ptr())).clone();
218          let e2_ptr = (*(self.e2.as_ptr())).clone();
219          let e3_ptr = (*(self.e3.as_ptr())).clone();
220          let mut out_ptr = (&mut *(self.out.as_mut_ptr()));
221          $opt!(out_ptr,e0_ptr,e1_ptr,e2_ptr,e3_ptr);
222        }
223      }
224      fn out(&self) -> Value { self.out.to_value() }
225      fn to_string(&self) -> String { format!("{:#?}", self) }
226    }
227    #[cfg(feature = "compiler")]
228    impl<T> MechFunctionCompiler for $fxn<T> 
229    where
230      T: ConstElem + CompileConst + AsValueKind
231    {
232      fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
233        let name = format!("{}<{}>", stringify!($fxn), T::as_value_kind());
234        compile_quadop!(name, self.out, self.e0, self.e1, self.e2, self.e3, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
235      }
236    }
237    register_vertical_concatenate_fxn!($fxn);
238  };}
239  
240// VerticalConcatenateTwoArgs -------------------------------------------------
241
242#[cfg(feature = "matrixd")]
243struct VerticalConcatenateTwoArgs<T> {
244  e0: Box<dyn CopyMat<T>>,
245  e1: Box<dyn CopyMat<T>>,
246  out: Ref<DMatrix<T>>,
247}
248#[cfg(feature = "matrixd")]
249impl<T> MechFunctionFactory for VerticalConcatenateTwoArgs<T>
250where
251  T: Debug + Clone + Sync + Send + PartialEq + 'static +
252  ConstElem + CompileConst + AsValueKind,
253  Ref<DMatrix<T>>: ToValue
254{
255  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
256    match args {
257      FunctionArgs::Binary(out, arg0, arg1) => {
258        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
259        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
260        let out: Ref<DMatrix<T>> = unsafe { out.as_unchecked() }.clone();
261        Ok(Box::new(Self { e0, e1, out }))
262      },
263      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 2, found: args.len()}, None).with_compiler_loc())
264    }
265  }
266}
267#[cfg(feature = "matrixd")]
268impl<T> MechFunctionImpl for VerticalConcatenateTwoArgs<T>
269where
270  T: Debug + Clone + Sync + Send + PartialEq + 'static,
271  Ref<DMatrix<T>>: ToValue
272{
273  fn solve(&self) {
274    let offset = self.e0.copy_into_row_major(&self.out,0);
275    self.e1.copy_into_row_major(&self.out,offset);
276  }
277  fn out(&self) -> Value { self.out.to_value() }
278  fn to_string(&self) -> String { format!("VerticalConcatenateTwoArgs\n{:#?}", self.out) }
279}
280#[cfg(feature = "matrixd")]
281#[cfg(feature = "compiler")]
282impl<T> MechFunctionCompiler for VerticalConcatenateTwoArgs<T> 
283where
284  T: ConstElem + CompileConst + AsValueKind + AsValueKind
285{
286  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
287    let mut registers = [0, 0, 0];
288
289    registers[0] = compile_register!(self.out, ctx);
290    registers[1] = compile_register_mat!(self.e0, ctx);
291    registers[2] = compile_register_mat!(self.e1, ctx);
292
293    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::VertCat));
294
295    ctx.emit_binop(
296      hash_str(&format!("VerticalConcatenateTwoArgs<{}>", T::as_value_kind())),
297      registers[0],
298      registers[1],
299      registers[2],
300    );
301
302    Ok(registers[0])    
303  }
304}
305#[cfg(feature = "matrixd")]
306register_vertical_concatenate_fxn!(VerticalConcatenateTwoArgs);
307
308// VerticalConcatenateThreeArgs -----------------------------------------------
309    
310#[cfg(feature = "matrixd")]
311struct VerticalConcatenateThreeArgs<T> {
312  e0: Box<dyn CopyMat<T>>,
313  e1: Box<dyn CopyMat<T>>,
314  e2: Box<dyn CopyMat<T>>,
315  out: Ref<DMatrix<T>>,
316}
317#[cfg(feature = "matrixd")]
318impl<T> MechFunctionFactory for VerticalConcatenateThreeArgs<T>
319where
320  T: Debug + Clone + Sync + Send + PartialEq + 'static +
321  ConstElem + CompileConst + AsValueKind,
322  Ref<DMatrix<T>>: ToValue
323{
324  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
325    match args {
326      FunctionArgs::Ternary(out, arg0, arg1, arg2) => {
327        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
328        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
329        let e2: Box<dyn CopyMat<T>> = unsafe { arg2.get_copyable_matrix_unchecked::<T>() };
330        let out: Ref<DMatrix<T>> = unsafe { out.as_unchecked() }.clone();
331        Ok(Box::new(Self { e0, e1, e2, out }))
332      },
333      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 3, found: args.len()}, None).with_compiler_loc())
334    }
335  }
336}
337#[cfg(feature = "matrixd")]
338impl<T> MechFunctionImpl for VerticalConcatenateThreeArgs<T>
339where
340  T: Debug + Clone + Sync + Send + PartialEq + 'static,
341  Ref<DMatrix<T>>: ToValue
342{
343  fn solve(&self) {
344    let mut offset = self.e0.copy_into_row_major(&self.out,0);
345    offset += self.e1.copy_into_row_major(&self.out,offset);
346    self.e2.copy_into_row_major(&self.out,offset);
347  }
348  fn out(&self) -> Value { self.out.to_value() }
349  fn to_string(&self) -> String { format!("VerticalConcatenateThreeArgs\n{:#?}", self.out) }
350}
351#[cfg(feature = "matrixd")]
352#[cfg(feature = "compiler")]
353impl<T> MechFunctionCompiler for VerticalConcatenateThreeArgs<T> 
354where
355  T: ConstElem + CompileConst + AsValueKind + AsValueKind
356{
357  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
358    let mut registers = [0, 0, 0, 0];
359
360    registers[0] = compile_register!(self.out, ctx);
361    registers[1] = compile_register_mat!(self.e0, ctx);
362    registers[2] = compile_register_mat!(self.e1, ctx);
363    registers[3] = compile_register_mat!(self.e2, ctx);
364
365    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::VertCat));
366
367    ctx.emit_ternop(
368      hash_str(&format!("VerticalConcatenateThreeArgs<{}>", T::as_value_kind())),
369      registers[0],
370      registers[1],
371      registers[2],
372      registers[3],
373    );
374    Ok(registers[0])    
375  }
376}
377#[cfg(feature = "matrixd")]
378register_vertical_concatenate_fxn!(VerticalConcatenateThreeArgs);
379
380// VerticalConcatenateFourArgs ------------------------------------------------
381
382#[cfg(feature = "matrixd")]
383struct VerticalConcatenateFourArgs<T> {
384  e0: Box<dyn CopyMat<T>>,
385  e1: Box<dyn CopyMat<T>>,
386  e2: Box<dyn CopyMat<T>>,
387  e3: Box<dyn CopyMat<T>>,
388  out: Ref<DMatrix<T>>,
389}
390#[cfg(feature = "matrixd")]
391impl<T> MechFunctionFactory for VerticalConcatenateFourArgs<T>
392where
393  T: Debug + Clone + Sync + Send + PartialEq + 'static +
394  ConstElem + CompileConst + AsValueKind,
395  Ref<DMatrix<T>>: ToValue
396{
397  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
398    match args {
399      FunctionArgs::Quaternary(out, arg0, arg1, arg2, arg3) => {
400        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
401        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
402        let e2: Box<dyn CopyMat<T>> = unsafe { arg2.get_copyable_matrix_unchecked::<T>() };
403        let e3: Box<dyn CopyMat<T>> = unsafe { arg3.get_copyable_matrix_unchecked::<T>() };
404        let out: Ref<DMatrix<T>> = unsafe { out.as_unchecked() }.clone();
405        Ok(Box::new(Self { e0, e1, e2, e3, out }))
406      },
407      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 4, found: args.len()}, None).with_compiler_loc())
408    }
409  }
410}
411#[cfg(feature = "matrixd")]
412impl<T> MechFunctionImpl for VerticalConcatenateFourArgs<T>
413where
414  T: Debug + Clone + Sync + Send + PartialEq + 'static,
415  Ref<DMatrix<T>>: ToValue
416{
417  fn solve(&self) {
418    let mut offset = self.e0.copy_into_row_major(&self.out,0);
419    offset += self.e1.copy_into_row_major(&self.out,offset);
420    offset += self.e2.copy_into_row_major(&self.out,offset);
421    self.e3.copy_into_row_major(&self.out,offset);
422
423  }
424  fn out(&self) -> Value { self.out.to_value() }
425  fn to_string(&self) -> String { format!("VerticalConcatenateFourArgs\n{:#?}", self.out) }
426}
427#[cfg(feature = "matrixd")]
428#[cfg(feature = "compiler")]
429impl<T> MechFunctionCompiler for VerticalConcatenateFourArgs<T> 
430where
431  T: ConstElem + CompileConst + AsValueKind
432{
433  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
434let mut registers = [0, 0, 0, 0, 0];
435
436    registers[0] = compile_register!(self.out, ctx);
437    registers[1] = compile_register_mat!(self.e0, ctx);
438    registers[2] = compile_register_mat!(self.e1, ctx);
439    registers[3] = compile_register_mat!(self.e2, ctx);
440    registers[4] = compile_register_mat!(self.e3, ctx);
441
442    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::VertCat));
443
444    ctx.emit_quadop(
445      hash_str(&format!("VerticalConcatenateFourArgs<{}>", T::as_value_kind())),
446      registers[0],
447      registers[1],
448      registers[2],
449      registers[3],
450      registers[4],
451    );
452    Ok(registers[0])
453  }
454}
455#[cfg(feature = "matrixd")]
456register_vertical_concatenate_fxn!(VerticalConcatenateFourArgs);
457
458// VerticalConcatenateNArgs ---------------------------------------------------
459
460#[cfg(feature = "matrixd")]
461struct VerticalConcatenateNArgs<T> {
462  e0: Vec<Box<dyn CopyMat<T>>>,
463  out: Ref<DMatrix<T>>,
464}
465#[cfg(feature = "matrixd")]
466impl<T> MechFunctionFactory for VerticalConcatenateNArgs<T>
467where
468  T: Debug + Clone + Sync + Send + PartialEq + 'static +
469  ConstElem + CompileConst + AsValueKind,
470  Ref<DMatrix<T>>: ToValue
471{
472  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
473    match args {
474      FunctionArgs::Variadic(out, arg0) => {
475        let mut e0: Vec<Box<dyn CopyMat<T>>> = Vec::new();
476        for arg in arg0 {
477          let mat: Box<dyn CopyMat<T>> = unsafe { arg.get_copyable_matrix_unchecked::<T>() };
478          e0.push(mat);
479        }
480        let out: Ref<DMatrix<T>> = unsafe { out.as_unchecked() }.clone();
481        Ok(Box::new(Self { e0, out }))
482      },
483      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 0, found: args.len()}, None).with_compiler_loc())
484    }
485  }
486}
487#[cfg(feature = "matrixd")]
488impl<T> MechFunctionImpl for VerticalConcatenateNArgs<T>
489where
490  T: Debug + Clone + Sync + Send + PartialEq + 'static,
491  Ref<DMatrix<T>>: ToValue
492{
493  fn solve(&self) {
494    let mut offset = 0;
495    for e in &self.e0 {
496      offset += e.copy_into_row_major(&self.out,offset);
497    }
498  }
499  fn out(&self) -> Value { self.out.to_value() }
500  fn to_string(&self) -> String { format!("VerticalConcatenateNArgs\n{:#?}", self.out) }
501}
502#[cfg(feature = "matrixd")]
503#[cfg(feature = "compiler")]
504impl<T> MechFunctionCompiler for VerticalConcatenateNArgs<T> 
505where
506  T: ConstElem + CompileConst + AsValueKind
507{
508  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
509    let mut registers = [0, 0];
510
511    registers[0] = compile_register!(self.out, ctx);
512
513    let mut mat_regs = Vec::new();
514    for e in &self.e0 {
515      let e_addr = e.addr();
516      let e_reg = ctx.alloc_register_for_ptr(e_addr);
517      let e_const_id = e.compile_const_mat(ctx).unwrap();
518      ctx.emit_const_load(e_reg, e_const_id);
519      mat_regs.push(e_reg);
520    }
521    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::HorzCat));
522    ctx.emit_varop(
523      hash_str(&format!("VerticalConcatenateNArgs<{}>", T::as_value_kind())),
524      registers[0],
525      mat_regs,
526    );
527    Ok(registers[0])
528  }
529}
530#[cfg(feature = "matrixd")]
531register_vertical_concatenate_fxn!(VerticalConcatenateNArgs);
532
533// VerticalConcatenateVec -----------------------------------------------------
534
535macro_rules! vertical_concatenate {
536  ($name:ident, $vec_size:expr) => {
537    paste!{
538      #[derive(Debug)]
539      struct $name<T> {
540        out: Ref<[<$vec_size>]<T>>,
541      }
542      impl<T> MechFunctionFactory for $name<T>
543      where
544        T: Debug + Clone + Sync + Send + PartialEq + 'static +
545        ConstElem + CompileConst + AsValueKind,
546        Ref<[<$vec_size>]<T>>: ToValue
547      {
548        fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
549          match args {
550            FunctionArgs::Unary(out, _arg0) => {
551              let out: Ref<[<$vec_size>]<T>> = unsafe { out.as_unchecked() }.clone();
552              Ok(Box::new(Self { out }))
553            },
554            _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 1, found: args.len()}, None).with_compiler_loc())
555          }
556        }
557      }
558      impl<T> MechFunctionImpl for $name<T> 
559      where
560        T: Debug + Clone + Sync + Send + PartialEq + 'static,
561        Ref<[<$vec_size>]<T>>: ToValue
562      {
563        fn solve(&self) {}
564        fn out(&self) -> Value { self.out.to_value() }
565        fn to_string(&self) -> String { format!("{:#?}", self) }
566      }
567      #[cfg(feature = "compiler")]
568      impl<T> MechFunctionCompiler for $name<T> 
569      where
570        T: ConstElem + CompileConst + AsValueKind + AsValueKind
571      {
572        fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
573          let name = format!("{}<{}>", stringify!($name), T::as_value_kind());
574          compile_unop!(name, self.out, self.out, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
575        }
576      }
577      register_vertical_concatenate_fxn!($name);
578    }
579  };}  
580
581// VerticalConcatenateVD2 -----------------------------------------------------
582
583#[cfg(feature = "vectord")]
584struct VerticalConcatenateVD2<T> {
585  e0: Box<dyn CopyMat<T>>,
586  e1: Box<dyn CopyMat<T>>,
587  out: Ref<DVector<T>>,
588}
589#[cfg(feature = "vectord")]
590impl<T> MechFunctionFactory for VerticalConcatenateVD2<T>
591where
592  T: Debug + Clone + Sync + Send + PartialEq + 'static +
593  ConstElem + CompileConst + AsValueKind,
594  Ref<DVector<T>>: ToValue
595{
596  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
597    match args {
598      FunctionArgs::Binary(out, arg0, arg1) => {
599        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
600        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
601        let out: Ref<DVector<T>> = unsafe { out.as_unchecked() }.clone();
602        Ok(Box::new(Self { e0, e1, out }))
603      },
604      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 2, found: args.len()}, None).with_compiler_loc())
605    }
606  }
607}
608#[cfg(feature = "vectord")]
609impl<T> MechFunctionImpl for VerticalConcatenateVD2<T> 
610where
611  T: Debug + Clone + Sync + Send + PartialEq + 'static,
612  Ref<DVector<T>>: ToValue
613{
614  fn solve(&self) {   
615    let mut offset = self.e0.copy_into_v(&self.out,0);
616    self.e1.copy_into_v(&self.out,offset);
617  }
618  fn out(&self) -> Value { self.out.to_value() }
619  fn to_string(&self) -> String { format!("VerticalConcatenateVD2\n{:#?}", self.out) }
620}
621#[cfg(feature = "vectord")]
622#[cfg(feature = "compiler")]
623impl<T> MechFunctionCompiler for VerticalConcatenateVD2<T> 
624where
625  T: ConstElem + CompileConst + AsValueKind
626{
627  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
628    let mut registers = [0, 0, 0];
629
630    registers[0] = compile_register!(self.out, ctx);
631
632    let lhs_addr = self.e0.addr();
633    let lhs_reg = ctx.alloc_register_for_ptr(lhs_addr);
634    let lhs_const_id = self.e0.compile_const_mat(ctx).unwrap();
635    ctx.emit_const_load(lhs_reg, lhs_const_id);
636    registers[1] = lhs_reg;
637
638    let rhs_addr = self.e1.addr();
639    let rhs_reg = ctx.alloc_register_for_ptr(rhs_addr);
640    let rhs_const_id = self.e1.compile_const_mat(ctx).unwrap();
641    ctx.emit_const_load(rhs_reg, rhs_const_id);
642    registers[2] = rhs_reg;
643
644    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::HorzCat));
645
646    ctx.emit_binop(
647      hash_str(&format!("VerticalConcatenateVD2<{}>", T::as_value_kind())),
648      registers[0],
649      registers[1],
650      registers[2],
651    );
652
653    Ok(registers[0])
654  }
655}
656#[cfg(feature = "vectord")]
657register_vertical_concatenate_fxn!(VerticalConcatenateVD2);
658
659// VerticalConcatenateVD3 -----------------------------------------------------
660
661#[cfg(feature = "vectord")]
662struct VerticalConcatenateVD3<T> {
663  e0: Box<dyn CopyMat<T>>,
664  e1: Box<dyn CopyMat<T>>,
665  e2: Box<dyn CopyMat<T>>,
666  out: Ref<DVector<T>>,
667}
668#[cfg(feature = "vectord")]
669impl<T> MechFunctionFactory for VerticalConcatenateVD3<T>
670where
671  T: Debug + Clone + Sync + Send + PartialEq + 'static +
672  ConstElem + CompileConst + AsValueKind,
673  Ref<DVector<T>>: ToValue
674{
675  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
676    match args {
677      FunctionArgs::Ternary(out, arg0, arg1, arg2) => {
678        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
679        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
680        let e2: Box<dyn CopyMat<T>> = unsafe { arg2.get_copyable_matrix_unchecked::<T>() };
681        let out: Ref<DVector<T>> = unsafe { out.as_unchecked() }.clone();
682        Ok(Box::new(Self { e0, e1, e2, out }))
683      },
684      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 3, found: args.len()}, None).with_compiler_loc())
685    }
686  }
687}
688#[cfg(feature = "vectord")]
689impl<T> MechFunctionImpl for VerticalConcatenateVD3<T>
690where
691  T: Debug + Clone + Sync + Send + PartialEq + 'static,
692  Ref<DVector<T>>: ToValue
693{
694  fn solve(&self) {   
695    let mut offset = self.e0.copy_into_v(&self.out,0);
696    offset += self.e1.copy_into_v(&self.out,offset);
697    self.e2.copy_into_v(&self.out,offset);
698  }
699  fn out(&self) -> Value { self.out.to_value() }
700  fn to_string(&self) -> String { format!("VerticalConcatenateVD3\n{:#?}", self.out) }
701}
702#[cfg(feature = "vectord")]
703#[cfg(feature = "compiler")]
704impl<T> MechFunctionCompiler for VerticalConcatenateVD3<T> 
705where
706  T: ConstElem + CompileConst + AsValueKind
707{
708  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
709    let mut registers = [0, 0, 0, 0];
710
711    registers[0] = compile_register!(self.out, ctx);
712    registers[1] = compile_register_mat!(self.e0, ctx);
713    registers[2] = compile_register_mat!(self.e1, ctx);
714    registers[3] = compile_register_mat!(self.e2, ctx);
715
716    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::HorzCat));
717
718    ctx.emit_ternop(
719      hash_str(&format!("VerticalConcatenateVD3<{}>", T::as_value_kind())),
720      registers[0],
721      registers[1],
722      registers[2],
723      registers[3],
724    );
725    Ok(registers[0])
726  }
727}
728#[cfg(feature = "vectord")]
729register_vertical_concatenate_fxn!(VerticalConcatenateVD3);
730
731// VerticalConcatenateVD4 -----------------------------------------------------
732
733#[cfg(feature = "vectord")]
734struct VerticalConcatenateVD4<T> {
735  e0: Box<dyn CopyMat<T>>,
736  e1: Box<dyn CopyMat<T>>,
737  e2: Box<dyn CopyMat<T>>,
738  e3: Box<dyn CopyMat<T>>,
739  out: Ref<DVector<T>>,
740}
741#[cfg(feature = "vectord")]
742impl<T> MechFunctionFactory for VerticalConcatenateVD4<T>
743where
744  T: Debug + Clone + Sync + Send + PartialEq + 'static +
745  ConstElem + CompileConst + AsValueKind,
746  Ref<DVector<T>>: ToValue
747{
748  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
749    match args {
750      FunctionArgs::Quaternary(out, arg0, arg1, arg2, arg3) => {
751        let e0: Box<dyn CopyMat<T>> = unsafe { arg0.get_copyable_matrix_unchecked::<T>() };
752        let e1: Box<dyn CopyMat<T>> = unsafe { arg1.get_copyable_matrix_unchecked::<T>() };
753        let e2: Box<dyn CopyMat<T>> = unsafe { arg2.get_copyable_matrix_unchecked::<T>() };
754        let e3: Box<dyn CopyMat<T>> = unsafe { arg3.get_copyable_matrix_unchecked::<T>() };
755        let out: Ref<DVector<T>> = unsafe { out.as_unchecked() }.clone();
756        Ok(Box::new(Self { e0, e1, e2, e3, out }))
757      },
758      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 4, found: args.len()}, None).with_compiler_loc())
759    }
760  }
761}
762#[cfg(feature = "vectord")]
763impl<T> MechFunctionImpl for VerticalConcatenateVD4<T>
764where
765  T: Debug + Clone + Sync + Send + PartialEq + 'static,
766  Ref<DVector<T>>: ToValue
767{
768  fn solve(&self) {   
769    let mut offset = self.e0.copy_into_v(&self.out,0);
770    offset += self.e1.copy_into_v(&self.out,offset);
771    offset += self.e2.copy_into_v(&self.out,offset);
772    self.e3.copy_into_v(&self.out,offset);
773  }
774  fn out(&self) -> Value { self.out.to_value() }
775  fn to_string(&self) -> String { format!("VerticalConcatenateVD3\n{:#?}", self.out) }
776}
777#[cfg(feature = "vectord")]
778#[cfg(feature = "compiler")]
779impl<T> MechFunctionCompiler for VerticalConcatenateVD4<T> 
780where
781  T: ConstElem + CompileConst + AsValueKind
782{
783  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
784    let mut registers = [0, 0, 0, 0, 0];
785
786    registers[0] = compile_register!(self.out, ctx);
787    registers[1] = compile_register_mat!(self.e0, ctx);
788    registers[2] = compile_register_mat!(self.e1, ctx);
789    registers[3] = compile_register_mat!(self.e2, ctx);
790    registers[4] = compile_register_mat!(self.e3, ctx);
791
792    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::HorzCat));
793
794    ctx.emit_quadop(
795      hash_str(&format!("VerticalConcatenateVD4<{}>", T::as_value_kind())),
796      registers[0],
797      registers[1],
798      registers[2],
799      registers[3],
800      registers[4],
801    );
802    Ok(registers[0])
803  }
804}
805#[cfg(feature = "vectord")]
806register_vertical_concatenate_fxn!(VerticalConcatenateVD4);
807
808// VerticalConcatenateVDN -----------------------------------------------------
809
810#[cfg(feature = "vectord")]
811struct VerticalConcatenateVDN<T> {
812  scalar: Vec<(Ref<T>,usize)>,
813  matrix: Vec<(Box<dyn CopyMat<T>>,usize)>,
814  out: Ref<DVector<T>>,
815}
816#[cfg(feature = "vectord")]
817impl<T> MechFunctionFactory for VerticalConcatenateVDN<T>
818where
819  T: Debug + Clone + Sync + Send + PartialEq + 'static +
820  ConstElem + CompileConst + AsValueKind,
821  Ref<DVector<T>>: ToValue
822{
823  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
824    match args {
825      FunctionArgs::Variadic(out, vargs) => {
826        let mut scalar: Vec<(Ref<T>,usize)> = Vec::new();
827        let mut matrix: Vec<(Box<dyn CopyMat<T>>,usize)> = Vec::new();
828        for (i, arg) in vargs.into_iter().enumerate() {
829          let kind = arg.kind();
830          if arg.is_scalar() {
831            let scalar_ref = unsafe { arg.as_unchecked::<T>() };
832            scalar.push((scalar_ref.clone(), i));
833          } else {
834            let mat_ref: Box<dyn CopyMat<T>> = unsafe { arg.get_copyable_matrix_unchecked::<T>() };
835            matrix.push((mat_ref, i));
836          }
837        }
838        let out: Ref<DVector<T>> = unsafe { out.as_unchecked() }.clone();
839        Ok(Box::new(Self { scalar, matrix, out }))
840      },
841      _ => Err(MechError2::new(IncorrectNumberOfArguments{expected: 0, found: args.len()}, None).with_compiler_loc())
842    }
843  }
844}
845#[cfg(feature = "vectord")]
846impl<T> MechFunctionImpl for VerticalConcatenateVDN<T>
847where
848  T: Debug + Clone + Sync + Send + PartialEq + 'static,
849  Ref<DVector<T>>: ToValue
850{
851  fn solve(&self) {
852    unsafe {
853      let mut out_ptr = (&mut *(self.out.as_mut_ptr()));
854      for (e,i) in &self.matrix {
855        e.copy_into_v(&self.out,*i);
856      }
857      for (e,i) in &self.scalar {
858        out_ptr[*i] = e.borrow().clone();
859      }
860    }
861  }
862  fn out(&self) -> Value { self.out.to_value() }
863  fn to_string(&self) -> String { format!("VerticalConcatenateVDN\n{:#?}", self.out) }
864}
865#[cfg(feature = "vectord")]
866#[cfg(feature = "compiler")]
867impl<T> MechFunctionCompiler for VerticalConcatenateVDN<T> 
868where
869  T: ConstElem + CompileConst + AsValueKind
870{
871  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
872    let mut registers = [0, 0];
873
874    registers[0] = compile_register!(self.out, ctx);
875
876    let mut mat_regs = Vec::new();
877    for (e,_) in &self.matrix {
878      mat_regs.push(compile_register_mat!(e, ctx));
879    }
880    ctx.features.insert(FeatureFlag::Builtin(FeatureKind::HorzCat));
881    ctx.emit_varop(
882      hash_str(&format!("VerticalConcatenateVDN<{}>", T::as_value_kind())),
883      registers[0],
884      mat_regs,
885    );
886    Ok(registers[0])
887  }
888}
889#[cfg(feature = "vectord")]
890register_vertical_concatenate_fxn!(VerticalConcatenateVDN);
891
892// VerticalConcatenateS1 ------------------------------------------------------
893
894#[cfg(feature = "matrix1")]
895#[derive(Debug)]
896struct VerticalConcatenateS1<T> {
897  out: Ref<Matrix1<T>>,
898}
899#[cfg(feature = "matrix1")]
900impl<T> MechFunctionFactory for VerticalConcatenateS1<T>
901where
902  T: Debug + Clone + Sync + Send + PartialEq + 'static +
903  ConstElem + CompileConst + AsValueKind,
904  Ref<Matrix1<T>>: ToValue
905{
906  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
907    match args {
908      FunctionArgs::Unary(out, _arg0) => {
909        let out: Ref<Matrix1<T>> = unsafe { out.as_unchecked() }.clone();
910        Ok(Box::new(Self { out }))
911      },
912      _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: format!("VerticalConcatenateS1 requires 1 argument, got {:?}", args), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments})
913    }
914  }
915}
916#[cfg(feature = "matrix1")]
917impl<T> MechFunctionImpl for VerticalConcatenateS1<T>
918where
919  T: Debug + Clone + Sync + Send + PartialEq + 'static,
920  Ref<Matrix1<T>>: ToValue
921{
922  fn solve(&self) {}
923  fn out(&self) -> Value { self.out.to_value() }
924  fn to_string(&self) -> String { format!("{:#?}", self) }
925}
926
927#[cfg(all(feature = "matrix1", feature = "compiler"))]
928impl<T> MechFunctionCompiler for VerticalConcatenateS1<T> 
929where
930  T: ConstElem + CompileConst + AsValueKind
931{
932  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
933    let name = format!("VerticalConcatenateS1<{}>", T::as_value_kind());
934    compile_nullop!(name, self.out, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
935  }
936}
937#[cfg(feature = "matrix1")]
938register_vertical_concatenate_fxn!(VerticalConcatenateS1);
939
940// VerticalConcatenateS2 ------------------------------------------------------
941
942#[cfg(feature = "vector2")]
943vertical_concatenate!(VerticalConcatenateS2,Vector2);
944
945// VerticalConcatenateS3 ------------------------------------------------------
946
947#[cfg(feature = "vector3")]
948vertical_concatenate!(VerticalConcatenateS3,Vector3);
949
950// VerticalConcatenateS4 ------------------------------------------------------
951
952#[cfg(feature = "vector4")]
953vertical_concatenate!(VerticalConcatenateS4,Vector4);
954
955// VerticalConcatenateV2 ------------------------------------------------------
956
957#[cfg(feature = "vector2")]
958vertical_concatenate!(VerticalConcatenateV2,Vector2);
959
960// VerticalConcatenateV3 ------------------------------------------------------
961
962#[cfg(feature = "vector3")]
963vertical_concatenate!(VerticalConcatenateV3,Vector3);
964
965// VerticalConcatenateV4 ------------------------------------------------------
966
967#[cfg(feature = "vector4")]
968vertical_concatenate!(VerticalConcatenateV4,Vector4);
969
970// VerticalConcatenateM2 ------------------------------------------------------
971
972#[cfg(feature = "matrix2")]
973vertical_concatenate!(VerticalConcatenateM2,Matrix2);
974
975// VerticalConcatenateM3 ------------------------------------------------------
976
977#[cfg(feature = "matrix3")]
978vertical_concatenate!(VerticalConcatenateM3,Matrix3);
979
980// VerticalConcatenateM2x3 ----------------------------------------------------
981
982#[cfg(feature = "matrix2x3")]
983vertical_concatenate!(VerticalConcatenateM2x3,Matrix2x3);
984
985// VerticalConcatenateM3x2 ----------------------------------------------------
986
987#[cfg(feature = "matrix3x2")]
988vertical_concatenate!(VerticalConcatenateM3x2,Matrix3x2);
989
990// VerticalConcatenateM4 ------------------------------------------------------
991
992#[cfg(feature = "matrix4")]
993vertical_concatenate!(VerticalConcatenateM4,Matrix4);
994
995// VerticalConcatenateMD ------------------------------------------------------
996
997#[cfg(feature = "matrixd")]
998vertical_concatenate!(VerticalConcatenateMD,DMatrix);
999
1000// VerticalConcatenateVD ------------------------------------------------------
1001
1002#[cfg(feature = "vectord")]
1003vertical_concatenate!(VerticalConcatenateVD,DVector);
1004
1005// VerticalConcatenateSD ------------------------------------------------------
1006
1007#[cfg(feature = "vectord")]
1008#[derive(Debug)]
1009struct VerticalConcatenateSD<T> {
1010  out: Ref<DVector<T>>,
1011}
1012#[cfg(feature = "vectord")]
1013impl<T> MechFunctionFactory for VerticalConcatenateSD<T>
1014where
1015  T: Debug + Clone + Sync + Send + PartialEq + 'static +
1016  ConstElem + CompileConst + AsValueKind,
1017  Ref<DVector<T>>: ToValue
1018{
1019  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
1020    match args {
1021      FunctionArgs::Unary(out, _arg0) => {
1022        let out: Ref<DVector<T>> = unsafe { out.as_unchecked() }.clone();
1023        Ok(Box::new(Self { out }))
1024      },
1025      _ => Err(MechError2::new(
1026          IncorrectNumberOfArguments { expected: 1, found: args.len() }, 
1027          None
1028        ).with_compiler_loc()
1029      ),
1030    }
1031  }
1032}
1033#[cfg(feature = "vectord")]
1034impl<T> MechFunctionImpl for VerticalConcatenateSD<T>
1035where
1036  T: Debug + Clone + Sync + Send + PartialEq + 'static,
1037  Ref<DVector<T>>: ToValue
1038{
1039  fn solve(&self) { }
1040  fn out(&self) -> Value { self.out.to_value() }
1041  fn to_string(&self) -> String { format!("{:#?}", self) }
1042}
1043#[cfg(all(feature = "vectord", feature = "compiler"))]
1044impl<T> MechFunctionCompiler for VerticalConcatenateSD<T> 
1045where
1046  T: ConstElem + CompileConst + AsValueKind
1047{
1048  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
1049    let name = format!("VerticalConcatenateSD<{}>", T::as_value_kind());
1050    compile_nullop!(name, self.out, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
1051  }
1052}
1053#[cfg(feature = "vectord")]
1054register_vertical_concatenate_fxn!(VerticalConcatenateSD);
1055
1056// VerticalConcatenateM1M1 ----------------------------------------------------
1057
1058macro_rules! vertcat_m1m1 {
1059  ($out:expr, $e0:expr, $e1:expr) => {
1060    $out[0] = $e0[0].clone();
1061    $out[1] = $e1[0].clone();
1062  };}
1063#[cfg(all(feature = "matrix1", feature = "vector2"))]
1064vertcat_two_args!(VerticalConcatenateM1M1,Matrix1,Matrix1,Vector2,vertcat_m1m1);
1065
1066// VerticalConcatenateV2V2 ----------------------------------------------------
1067
1068macro_rules! vertcat_r2r2 {
1069  ($out:expr, $e0:expr, $e1:expr) => {
1070    $out[0] = $e0[0].clone();
1071    $out[1] = $e0[1].clone();
1072    $out[2] = $e1[0].clone();
1073    $out[3] = $e1[1].clone();
1074  };}
1075#[cfg(all(feature = "vector2", feature = "vector4"))]
1076vertcat_two_args!(VerticalConcatenateV2V2,Vector2,Vector2,Vector4,vertcat_r2r2);
1077
1078// VerticalConcatenateM1V3 ----------------------------------------------------
1079
1080macro_rules! vertcat_m1r3 {
1081  ($out:expr, $e0:expr, $e1:expr) => {
1082    $out[0] = $e0[0].clone();
1083    $out[1] = $e1[0].clone();
1084    $out[2] = $e1[1].clone();
1085    $out[3] = $e1[2].clone();
1086  };}
1087#[cfg(all(feature = "matrix1", feature = "vector3", feature = "vector4"))]
1088vertcat_two_args!(VerticalConcatenateM1V3,Matrix1,Vector3,Vector4,vertcat_m1r3);
1089
1090// VerticalConcatenateV3M1 ----------------------------------------------------
1091
1092macro_rules! vertcat_r3m1 {
1093  ($out:expr, $e0:expr, $e1:expr) => {
1094    $out[0] = $e0[0].clone();
1095    $out[1] = $e0[1].clone();
1096    $out[2] = $e0[2].clone();
1097    $out[3] = $e1[0].clone();
1098  };}
1099#[cfg(all(feature = "vector3", feature = "matrix1", feature = "vector4"))]
1100vertcat_two_args!(VerticalConcatenateV3M1,Vector3,Matrix1,Vector4,vertcat_r3m1);
1101
1102// VerticalConcatenateM1V2 ----------------------------------------------------
1103
1104macro_rules! vertcat_m1r2 {
1105  ($out:expr, $e0:expr, $e1:expr) => {
1106    $out[0] = $e0[0].clone();
1107    $out[1] = $e1[0].clone();
1108    $out[2] = $e1[1].clone();
1109  };
1110}
1111#[cfg(all(feature = "matrix1", feature = "vector2", feature = "vector3"))]
1112vertcat_two_args!(VerticalConcatenateM1V2, Matrix1, Vector2, Vector3, vertcat_m1r2);
1113
1114// VerticalConcatenateV2M1 ----------------------------------------------------
1115
1116macro_rules! vertcat_r2m1 {
1117  ($out:expr, $e0:expr, $e1:expr) => {
1118    $out[0] = $e0[0].clone();
1119    $out[1] = $e0[1].clone();
1120    $out[2] = $e1[0].clone();
1121  };
1122}
1123#[cfg(all(feature = "vector2", feature = "matrix1", feature = "vector3"))]
1124vertcat_two_args!(VerticalConcatenateV2M1, Vector2, Matrix1, Vector3, vertcat_r2m1);
1125
1126// VerticalConcatenateM1M1M1 --------------------------------------------------
1127
1128macro_rules! vertcat_m1m1m1 {
1129  ($out:expr, $e0:expr,$e1:expr,$e2:expr) => {
1130    $out[0] = $e0[0].clone();
1131    $out[1] = $e1[0].clone();
1132    $out[2] = $e2[0].clone();
1133  };
1134}
1135#[cfg(all(feature = "matrix1", feature = "vector3"))]
1136vertcat_three_args!(VerticalConcatenateM1M1M1,Matrix1,Matrix1,Matrix1,Vector3, vertcat_m1m1m1);
1137
1138// VerticalConcatenateM1M1V2 --------------------------------------------------
1139
1140macro_rules! vertcat_m1m1v2 {
1141  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
1142    $out[0] = $e0[0].clone();
1143    $out[1] = $e1[0].clone();
1144    $out[2] = $e2[0].clone();
1145    $out[3] = $e2[1].clone();
1146  };
1147}
1148#[cfg(all(feature = "matrix1", feature = "vector2", feature = "vector4"))]
1149vertcat_three_args!(VerticalConcatenateM1M1V2, Matrix1, Matrix1, Vector2, Vector4, vertcat_m1m1v2);
1150
1151// VerticalConcatenateM1V2M1 --------------------------------------------------
1152
1153macro_rules! vertcat_m1r2m1 {
1154  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
1155    $out[0] = $e0[0].clone();
1156    $out[1] = $e1[0].clone();
1157    $out[2] = $e1[1].clone();
1158    $out[3] = $e2[0].clone();
1159  };
1160}
1161#[cfg(all(feature = "matrix1", feature = "vector2", feature = "vector4"))]
1162vertcat_three_args!(VerticalConcatenateM1V2M1, Matrix1, Vector2, Matrix1, Vector4, vertcat_m1r2m1);
1163
1164// VerticalConcatenateV2M1M1 --------------------------------------------------
1165
1166macro_rules! vertcat_r2m1m1 {
1167  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
1168    $out[0] = $e0[0].clone();
1169    $out[1] = $e0[1].clone();
1170    $out[2] = $e1[0].clone();
1171    $out[3] = $e2[0].clone();
1172  };
1173}
1174#[cfg(all(feature = "vector2", feature = "matrix1", feature = "vector4"))]
1175vertcat_three_args!(VerticalConcatenateV2M1M1, Vector2, Matrix1, Matrix1, Vector4, vertcat_r2m1m1);
1176
1177// VerticalConcatenateM1M1M1M1 ------------------------------------------------
1178
1179#[cfg(all(feature = "matrix1", feature = "vector4"))]
1180#[derive(Debug)]
1181struct VerticalConcatenateM1M1M1M1<T> {
1182  e0: Ref<Matrix1<T>>,
1183  e1: Ref<Matrix1<T>>,
1184  e2: Ref<Matrix1<T>>,
1185  e3: Ref<Matrix1<T>>,
1186  out: Ref<Vector4<T>>,
1187}
1188#[cfg(all(feature = "matrix1", feature = "vector4"))]
1189impl<T> MechFunctionFactory for VerticalConcatenateM1M1M1M1<T>
1190where
1191  T: Debug + Clone + Sync + Send + PartialEq + 'static +
1192  ConstElem + CompileConst + AsValueKind,
1193  Ref<Vector4<T>>: ToValue
1194{
1195  fn new(args: FunctionArgs) -> MResult<Box<dyn MechFunction>> {
1196    match args {
1197      FunctionArgs::Quaternary(out, arg0, arg1, arg2, arg3) => {
1198        let e0: Ref<Matrix1<T>> = unsafe { arg0.as_unchecked() }.clone();
1199        let e1: Ref<Matrix1<T>> = unsafe { arg1.as_unchecked() }.clone();
1200        let e2: Ref<Matrix1<T>> = unsafe { arg2.as_unchecked() }.clone();
1201        let e3: Ref<Matrix1<T>> = unsafe { arg3.as_unchecked() }.clone();
1202        let out: Ref<Vector4<T>> = unsafe { out.as_unchecked() }.clone();
1203        Ok(Box::new(Self { e0, e1, e2, e3, out }))
1204      },
1205      _ => Err(MechError{file: file!().to_string(), tokens: vec![], msg: format!("VerticalConcatenateM1M1M1M1 requires 4 arguments, got {:?}", args), id: line!(), kind: MechErrorKind::IncorrectNumberOfArguments})
1206    }
1207  }
1208}
1209#[cfg(all(feature = "matrix1", feature = "vector4"))]
1210impl<T> MechFunctionImpl for VerticalConcatenateM1M1M1M1<T>
1211where
1212  T: Debug + Clone + Sync + Send + PartialEq + 'static,
1213  Ref<Vector4<T>>: ToValue
1214{
1215  fn solve(&self) { 
1216    unsafe {
1217      let e0_ptr = (*(self.e0.as_ptr())).clone();
1218      let e1_ptr = (*(self.e1.as_ptr())).clone();
1219      let e2_ptr = (*(self.e2.as_ptr())).clone();
1220      let e3_ptr = (*(self.e3.as_ptr())).clone();
1221      let mut out_ptr = (&mut *(self.out.as_mut_ptr()));
1222      out_ptr[0] = e0_ptr[0].clone();
1223      out_ptr[1] = e1_ptr[0].clone();
1224      out_ptr[2] = e2_ptr[0].clone();
1225      out_ptr[3] = e3_ptr[0].clone();
1226    }
1227  }
1228  fn out(&self) -> Value { self.out.to_value() }
1229  fn to_string(&self) -> String { format!("{:#?}", self) }
1230}
1231#[cfg(all(feature = "matrix1", feature = "vector4", feature = "compiler"))]
1232impl<T> MechFunctionCompiler for VerticalConcatenateM1M1M1M1<T> 
1233where
1234  T: ConstElem + CompileConst + AsValueKind
1235{
1236  fn compile(&self, ctx: &mut CompileCtx) -> MResult<Register> {
1237    let name = format!("VerticalConcatenateM1M1M1M1<{}>", T::as_value_kind());
1238    compile_quadop!(name, self.out, self.e0, self.e1, self.e2, self.e3, ctx, FeatureFlag::Builtin(FeatureKind::VertCat));
1239  }
1240}
1241#[cfg(all(feature = "matrix1", feature = "vector4"))]
1242register_vertical_concatenate_fxn!(VerticalConcatenateM1M1M1M1);
1243
1244// Mixed Type Vertical Concatenations -----------------------------------------
1245
1246macro_rules! vertcat_r2r2 {
1247  ($out:expr, $e0:expr, $e1:expr) => {
1248    $out[0] = $e0[0].clone();
1249    $out[2] = $e0[1].clone();
1250    $out[1] = $e1[0].clone();
1251    $out[3] = $e1[1].clone();
1252  };
1253}
1254#[cfg(all(feature = "row_vector2", feature = "matrix2"))]
1255vertcat_two_args!(VerticalConcatenateR2R2, RowVector2, RowVector2, Matrix2, vertcat_r2r2);
1256
1257// VerticalConcatenateR3R3 ----------------------------------------------------
1258
1259macro_rules! vertcat_r3r3 {
1260  ($out:expr, $e0:expr, $e1:expr) => {
1261    $out[0] = $e0[0].clone();
1262    $out[2] = $e0[1].clone();
1263    $out[4] = $e0[2].clone();
1264    $out[1] = $e1[0].clone();
1265    $out[3] = $e1[1].clone();
1266    $out[5] = $e1[2].clone();
1267  };
1268}
1269#[cfg(all(feature = "row_vector3", feature = "matrix2x3"))]
1270vertcat_two_args!(VerticalConcatenateR3R3, RowVector3, RowVector3, Matrix2x3, vertcat_r3r3);
1271
1272// VerticalConcatenateR2M2 ----------------------------------------------------
1273
1274macro_rules! vertcat_r2m2 {
1275  ($out:expr, $e0:expr, $e1:expr) => {
1276    $out[0] = $e0[0].clone();
1277    $out[3] = $e0[1].clone();
1278    $out[1] = $e1[0].clone();
1279    $out[2] = $e1[1].clone();
1280    $out[4] = $e1[2].clone();
1281    $out[5] = $e1[3].clone();
1282  };
1283}
1284#[cfg(all(feature = "row_vector2", feature = "matrix2", feature = "matrix3x2"))]
1285vertcat_two_args!(VerticalConcatenateR2M2, RowVector2, Matrix2, Matrix3x2, vertcat_r2m2);
1286
1287// VerticalConcatenateM2R2 ----------------------------------------------------
1288
1289macro_rules! vertcat_m2r2 {
1290  ($out:expr, $e0:expr, $e1:expr) => {
1291    $out[0] = $e0[0].clone();
1292    $out[1] = $e0[1].clone();
1293    $out[3] = $e0[2].clone();
1294    $out[4] = $e0[3].clone();
1295    $out[2] = $e1[0].clone();
1296    $out[5] = $e1[1].clone();
1297  };
1298}
1299#[cfg(all(feature = "matrix2", feature = "row_vector2", feature = "matrix3x2"))]
1300vertcat_two_args!(VerticalConcatenateM2R2, Matrix2, RowVector2, Matrix3x2, vertcat_m2r2);
1301
1302// VerticalConcatenateM2x3R3 --------------------------------------------------
1303
1304macro_rules! vertcat_m2x3r3 {
1305  ($out:expr, $e0:expr, $e1:expr) => {
1306    $out[0] = $e0[0].clone();
1307    $out[1] = $e0[1].clone();
1308    $out[3] = $e0[2].clone();
1309    $out[4] = $e0[3].clone();
1310    $out[6] = $e0[4].clone();
1311    $out[7] = $e0[5].clone();
1312    $out[2] = $e1[0].clone();
1313    $out[5] = $e1[1].clone();
1314    $out[8] = $e1[2].clone();
1315  };
1316}
1317#[cfg(all(feature = "matrix2x3", feature = "row_vector3", feature = "matrix3"))]
1318vertcat_two_args!(VerticalConcatenateM2x3R3, Matrix2x3, RowVector3, Matrix3, vertcat_m2x3r3);
1319
1320// VerticalConcatenateR3M2x3 --------------------------------------------------
1321
1322macro_rules! vertcat_r3m2x3 {
1323  ($out:expr, $e0:expr, $e1:expr) => {
1324    $out[0] = $e0[0].clone();
1325    $out[3] = $e0[1].clone();
1326    $out[6] = $e0[2].clone();
1327    $out[1] = $e1[0].clone();
1328    $out[2] = $e1[1].clone();
1329    $out[4] = $e1[2].clone();
1330    $out[5] = $e1[3].clone();
1331    $out[7] = $e1[4].clone();
1332    $out[8] = $e1[5].clone();
1333  };
1334}
1335#[cfg(all(feature = "row_vector3", feature = "matrix2x3", feature = "matrix3"))]
1336vertcat_two_args!(VerticalConcatenateR3M2x3, RowVector3, Matrix2x3, Matrix3, vertcat_r3m2x3);
1337
1338// VerticalConcatenateMDR4 ----------------------------------------------------
1339
1340macro_rules! vertcat_mdr4 {
1341  ($out:expr, $e0:expr, $e1:expr) => {
1342    let e0_len = $e0.len();
1343    for i in 0..e0_len {
1344      $out[i] = $e0[i].clone();
1345    }
1346    let offset = e0_len;
1347    $out[offset] = $e1[0].clone();
1348    $out[offset + 1] = $e1[1].clone();
1349    $out[offset + 2] = $e1[2].clone();
1350    $out[offset + 3] = $e1[3].clone();
1351  };
1352}
1353#[cfg(all(feature = "matrixd", feature = "row_vector4", feature = "matrix4"))]
1354vertcat_two_args!(VerticalConcatenateMDR4, DMatrix, RowVector4, Matrix4, vertcat_mdr4);
1355
1356// VerticalConcatenateMDMD ----------------------------------------------------
1357
1358macro_rules! vertcat_mdmd {
1359  ($out:expr, $e0:expr, $e1:expr) => {
1360    let dest_rows = $out.nrows();
1361    let mut offset = 0;
1362    let mut dest_ix = 0;
1363
1364    let src_rows = $e0.nrows();
1365    let stride = dest_rows - src_rows;
1366    dest_ix = offset;
1367    for ix in 0..$e0.len() {
1368      $out[dest_ix] = $e0[ix].clone();
1369      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1370    }
1371    offset += src_rows;
1372
1373    let src_rows = $e1.nrows();
1374    let stride = dest_rows - src_rows;
1375    dest_ix = offset;
1376    for ix in 0..$e1.len() {
1377      $out[dest_ix] = $e1[ix].clone();
1378      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1379    }
1380  };
1381}
1382#[cfg(all(feature = "matrixd", feature = "matrix4"))]
1383vertcat_two_args!(VerticalConcatenateMDMD, DMatrix, DMatrix, Matrix4, vertcat_mdmd);
1384
1385// VerticalConcatenateR4MD ----------------------------------------------------
1386
1387#[cfg(all(feature = "matrixd", feature = "matrix4", feature = "row_vector4"))]
1388vertcat_two_args!(VerticalConcatenateR4MD, RowVector4, DMatrix, Matrix4, vertcat_mdmd);
1389
1390// VerticalConcatenateR2R2R2 ----------------------------------------------------
1391
1392macro_rules! vertcat_mdmdmd {
1393  ($out:expr, $e0:expr, $e1:expr, $e2:expr) => {
1394    let dest_rows = $out.nrows();
1395    let mut offset = 0;
1396    let mut dest_ix = 0;
1397
1398    let src_rows = $e0.nrows();
1399    let stride = dest_rows - src_rows;
1400    dest_ix = offset;
1401    for ix in 0..$e0.len() {
1402      $out[dest_ix] = $e0[ix].clone();
1403      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1404    }
1405    offset += src_rows;
1406
1407    let src_rows = $e1.nrows();
1408    let stride = dest_rows - src_rows;
1409    dest_ix = offset;
1410    for ix in 0..$e1.len() {
1411      $out[dest_ix] = $e1[ix].clone();
1412      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1413    }
1414    offset += src_rows;
1415
1416    let src_rows = $e2.nrows();
1417    let stride = dest_rows - src_rows;
1418    dest_ix = offset;
1419    for ix in 0..$e2.len() {
1420      $out[dest_ix] = $e2[ix].clone();
1421      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1422    }
1423  };
1424}
1425
1426#[cfg(all(feature = "row_vector2", feature = "matrix3x2"))]
1427vertcat_three_args!(VerticalConcatenateR2R2R2, RowVector2, RowVector2, RowVector2, Matrix3x2, vertcat_mdmdmd);
1428
1429// VerticalConcatenateR3R3R3 --------------------------------------------------
1430
1431#[cfg(all(feature = "row_vector3", feature = "matrix3"))]
1432vertcat_three_args!(VerticalConcatenateR3R3R3, RowVector3, RowVector3, RowVector3, Matrix3, vertcat_mdmdmd);
1433
1434// VerticalConcatenateR4R4MD --------------------------------------------------
1435
1436#[cfg(all(feature = "row_vector4", feature = "matrixd", feature = "matrix4"))]
1437vertcat_three_args!(VerticalConcatenateR4R4MD, RowVector4, RowVector4, DMatrix, Matrix4, vertcat_mdmdmd);
1438
1439// VerticalConcatenateR4MDR4 --------------------------------------------------
1440
1441#[cfg(all(feature = "row_vector4", feature = "matrixd", feature = "row_vector4", feature = "matrix4"))]
1442vertcat_three_args!(VerticalConcatenateR4MDR4, RowVector4, DMatrix, RowVector4, Matrix4, vertcat_mdmdmd);
1443
1444// VerticalConcatenateMDR4R4 --------------------------------------------------
1445
1446#[cfg(all(feature = "matrixd", feature = "row_vector4", feature = "row_vector4", feature = "matrix4"))]
1447vertcat_three_args!(VerticalConcatenateMDR4R4, DMatrix, RowVector4, RowVector4, Matrix4, vertcat_mdmdmd);
1448
1449// VerticalConcatenateR4R4R4R4 ------------------------------------------------
1450
1451macro_rules! vertcat_mdmdmdmd {
1452  ($out:expr, $e0:expr, $e1:expr, $e2:expr, $e3:expr) => {
1453    let dest_rows = $out.nrows();
1454    let mut offset = 0;
1455    let mut dest_ix = 0;
1456
1457    let src_rows = $e0.nrows();
1458    let stride = dest_rows - src_rows;
1459    dest_ix = offset;
1460    for ix in 0..$e0.len() {
1461      $out[dest_ix] = $e0[ix].clone();
1462      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1463    }
1464    offset += src_rows;
1465
1466    let src_rows = $e1.nrows();
1467    let stride = dest_rows - src_rows;
1468    dest_ix = offset;
1469    for ix in 0..$e1.len() {
1470      $out[dest_ix] = $e1[ix].clone();
1471      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1472    }
1473    offset += src_rows;
1474
1475    let src_rows = $e2.nrows();
1476    let stride = dest_rows - src_rows;
1477    dest_ix = offset;
1478    for ix in 0..$e2.len() {
1479      $out[dest_ix] = $e2[ix].clone();
1480      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1481    }
1482    offset += src_rows;
1483
1484    let src_rows = $e3.nrows();
1485    let stride = dest_rows - src_rows;
1486    dest_ix = offset;
1487    for ix in 0..$e3.len() {
1488      $out[dest_ix] = $e3[ix].clone();
1489      dest_ix += ((ix + 1) % src_rows == 0) as usize * stride + 1;
1490    }
1491  };
1492}
1493
1494#[cfg(all(feature = "matrix4", feature = "row_vector4"))]
1495vertcat_four_args!(VerticalConcatenateR4R4R4R4, RowVector4, RowVector4, RowVector4, RowVector4, Matrix4, vertcat_mdmdmdmd);
1496
1497macro_rules! impl_vertcat_arms {
1498  ($kind:ident, $args:expr, $default:expr) => {
1499    paste!{
1500    {
1501      let arguments = $args;  
1502      let rows = arguments[0].shape()[0];
1503      let rows:usize = arguments.iter().fold(0, |acc, x| acc + x.shape()[0]);
1504      let columns:usize = arguments[0].shape()[1];
1505      let nargs = arguments.len();
1506      let kinds: Vec<ValueKind> = arguments.iter().map(|x| x.kind()).collect::<Vec<ValueKind>>();
1507      let no_refs = !kinds.iter().any(|x| {
1508        match x {
1509          ValueKind::Reference(_) => true,
1510          ValueKind::Matrix(_,_) => true,
1511          _ => false,
1512      }});
1513      if no_refs {
1514        let mat: Vec<$kind> = arguments.iter().flat_map(|v| v.[<as_vec $kind:lower>]().unwrap()).collect::<Vec<$kind>>();
1515        fn to_column_major<T: Clone>(out: &[Value], row_n: usize, col_n: usize, extract_fn: impl Fn(&Value) -> MResult<Vec<T>> + Clone) -> Vec<T> {
1516          (0..col_n).flat_map(|col| out.iter().map({let value = extract_fn.clone();move |row| value(row).unwrap()[col].clone()})).collect()
1517        }
1518        let mat = to_column_major(&arguments, rows, columns, |v| v.[<as_vec $kind:lower>]());
1519        match (rows,columns) {
1520          #[cfg(feature = "matrix1")]
1521          (1,1) => {return Ok(Box::new(VerticalConcatenateS1{out:Ref::new(Matrix1::from_vec(mat))}));}
1522          #[cfg(feature = "vector2")]
1523          (2,1) => {return Ok(Box::new(VerticalConcatenateS2{out:Ref::new(Vector2::from_vec(mat))}));}
1524          #[cfg(feature = "vector3")]
1525          (3,1) => {return Ok(Box::new(VerticalConcatenateS3{out:Ref::new(Vector3::from_vec(mat))}));}
1526          #[cfg(feature = "vector4")]
1527          (4,1) => {return Ok(Box::new(VerticalConcatenateS4{out:Ref::new(Vector4::from_vec(mat))}));}
1528          #[cfg(feature = "vectord")]
1529          (m,1) => {return Ok(Box::new(VerticalConcatenateSD{out:Ref::new(DVector::from_vec(mat))}));}
1530          #[cfg(feature = "matrix2")]
1531          (2,2) => {return Ok(Box::new(VerticalConcatenateM2{out:Ref::new(Matrix2::from_vec(mat))}));}
1532          #[cfg(feature = "matrix3")]
1533          (3,3) => {return Ok(Box::new(VerticalConcatenateM3{out:Ref::new(Matrix3::from_vec(mat))}));}
1534          #[cfg(feature = "matrix4")]
1535          (4,4) => {return Ok(Box::new(VerticalConcatenateM4{out:Ref::new(Matrix4::from_vec(mat))}));}
1536          #[cfg(feature = "matrix2x3")]
1537          (2,3) => {return Ok(Box::new(VerticalConcatenateM2x3{out:Ref::new(Matrix2x3::from_vec(mat))}));}
1538          #[cfg(feature = "matrix3x2")]
1539          (3,2) => {return Ok(Box::new(VerticalConcatenateM3x2{out:Ref::new(Matrix3x2::from_vec(mat))}));}
1540          #[cfg(feature = "matrixd")]
1541          (m,n) => {return Ok(Box::new(VerticalConcatenateMD{out:Ref::new(DMatrix::from_vec(m,n,mat))}));}
1542          _ => Err(MechError2::new(
1543            FeatureNotEnabledError,
1544            None
1545          ).with_compiler_loc()),
1546        }
1547      } else {
1548        match (nargs,rows,columns) {
1549          #[cfg(feature = "vector2")]
1550          (1,2,1) => {
1551            match &arguments[..] {
1552              // r2
1553              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0))] => {
1554                return Ok(Box::new(VerticalConcatenateV2{out: e0.clone()}));
1555              }
1556              _ => todo!(),
1557            }
1558          }
1559          #[cfg(feature = "vector3")]
1560          (1,3,1) => {
1561            match &arguments[..] {
1562              // r3
1563              [Value::MutableReference(e0)] => {
1564                match *e0.borrow() {
1565                  Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e0)) => {
1566                    return Ok(Box::new(VerticalConcatenateV3{out: e0.clone()}));
1567                  }
1568                  _ => todo!(),
1569                }
1570              }
1571              _ => todo!(),
1572            }
1573          }
1574          #[cfg(feature = "vector4")]
1575          (1,4,1) => {
1576            match &arguments[..] {
1577              // r4
1578              [Value::[<Matrix $kind:camel>](Matrix::Vector4(ref e0))] => {
1579                return Ok(Box::new(VerticalConcatenateV4{out: e0.clone()}));
1580              }
1581              _ => todo!(),
1582            }
1583          }
1584          #[cfg(feature = "vectord")]
1585          (1,m,1) => {
1586            match &arguments[..] {
1587              // rd
1588              [Value::[<Matrix $kind:camel>](Matrix::DVector(ref e0))] => {
1589                return Ok(Box::new(VerticalConcatenateVD{out: e0.clone()}));
1590              }
1591              _ => todo!(),
1592            }
1593          }
1594          #[cfg(all(feature = "matrix1", feature = "vector2"))]
1595          (2,2,1) => {
1596            let mut out = Vector2::from_element($default);
1597            match &arguments[..] {
1598              // m1m1
1599              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
1600                return Ok(Box::new(VerticalConcatenateM1M1{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1601              }
1602              _ => todo!(),
1603            }
1604          }
1605          #[cfg(all(feature = "matrix1", feature = "vector3", feature = "vector2"))]
1606          (2,3,1) => {
1607            let mut out = Vector3::from_element($default);
1608            match &arguments[..] {
1609              //m1v2
1610              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1))] => {
1611                return Ok(Box::new(VerticalConcatenateM1V2{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1612              }
1613              //v2m1
1614              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
1615                return Ok(Box::new(VerticalConcatenateV2M1{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1616              }
1617              _ => todo!(),
1618            }
1619          }
1620          #[cfg(feature = "vector4")]
1621          (2,4,1) => {
1622            let mut out = Vector4::from_element($default);
1623            match &arguments[..] {
1624              // m1v3
1625              #[cfg(all(feature = "matrix1", feature = "vector3"))]
1626              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e1))] => {
1627                return Ok(Box::new(VerticalConcatenateM1V3{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1628              }
1629              // v3m1
1630              #[cfg(all(feature = "matrix1", feature = "vector3"))]
1631              [Value::[<Matrix $kind:camel>](Matrix::Vector3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1))] => {
1632                return Ok(Box::new(VerticalConcatenateV3M1{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1633              }
1634              // v2v2
1635              #[cfg(feature = "vector2")]
1636              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1))] => {
1637                return Ok(Box::new(VerticalConcatenateV2V2{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1638              }              
1639              _ => todo!(),
1640            }
1641          } 
1642          #[cfg(feature = "vectord")]
1643          (2,m,1) => {
1644            let mut out = DVector::from_element(m,$default);
1645            match &arguments[..] {
1646              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1)] => {
1647                let e0 = e0.get_copyable_matrix();
1648                let e1 = e1.get_copyable_matrix();
1649                return Ok(Box::new(VerticalConcatenateVD2{e0, e1, out: Ref::new(out)}));
1650              }
1651              _ => todo!(),
1652            }
1653          }
1654          #[cfg(feature = "vector3")]
1655          (3,3,1) => {  
1656            let mut out = Vector3::from_element($default);
1657            match &arguments[..] {
1658              // m1 m1 m1
1659              #[cfg(feature = "matrix1")]
1660              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)), Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
1661                return Ok(Box::new(VerticalConcatenateM1M1M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: Ref::new(out)}));
1662              }    
1663              _ => todo!()
1664            }
1665          }
1666          #[cfg(all(feature = "matrix1", feature = "vector2", feature = "vector4"))]
1667          (3,4,1) => {
1668            let mut out = Vector4::from_element($default);
1669            match &arguments[..] {
1670              // m1 m1 v2
1671              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e2))] => {
1672                return Ok(Box::new(VerticalConcatenateM1M1V2{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: Ref::new(out)}));
1673              }
1674              // m1 v2 m1
1675              [Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
1676                return Ok(Box::new(VerticalConcatenateM1V2M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: Ref::new(out)}));
1677              }
1678              // v2 m1 m1
1679              [Value::[<Matrix $kind:camel>](Matrix::Vector2(ref e0)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e1)),Value::[<Matrix $kind:camel>](Matrix::Matrix1(ref e2))] => {
1680                return Ok(Box::new(VerticalConcatenateV2M1M1{e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), out: Ref::new(out)}));
1681              }
1682              _ => todo!()
1683            }
1684          }
1685          #[cfg(feature = "vectord")]
1686          (3,m,1) => {
1687            let mut out = DVector::from_element(m,$default);
1688            match &arguments[..] {
1689              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1),Value::[<Matrix $kind:camel>](e2)] => {
1690                let e0 = e0.get_copyable_matrix();
1691                let e1 = e1.get_copyable_matrix();
1692                let e2 = e2.get_copyable_matrix();
1693                return Ok(Box::new(VerticalConcatenateVD3{e0, e1, e2, out: Ref::new(out)}));
1694              }
1695              _ => todo!(),
1696            }
1697          }
1698          #[cfg(all(feature = "matrix1", feature = "vector4"))]
1699          (4,4,1) => {
1700            let mut out = Vector4::from_element($default);
1701            match &arguments[..] {
1702              // m1 m1 m1 m1
1703              [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))] => {
1704                return Ok(Box::new(VerticalConcatenateM1M1M1M1{ e0: e0.clone(), e1: e1.clone(), e2: e2.clone(), e3: e3.clone(), out: Ref::new(out) }));
1705              }
1706              _ => todo!(),
1707            }
1708          }
1709          #[cfg(feature = "vectord")]
1710          (4,m,1) => {
1711            let mut out = DVector::from_element(m,$default);
1712            match &arguments[..] {
1713              [Value::[<Matrix $kind:camel>](e0),Value::[<Matrix $kind:camel>](e1),Value::[<Matrix $kind:camel>](e2),Value::[<Matrix $kind:camel>](e3)] => {
1714                let e0 = e0.get_copyable_matrix();
1715                let e1 = e1.get_copyable_matrix();
1716                let e2 = e2.get_copyable_matrix();
1717                let e3 = e3.get_copyable_matrix();
1718                return Ok(Box::new(VerticalConcatenateVD4{e0, e1, e2, e3, out: Ref::new(out)}));
1719              }
1720              _ => todo!(),
1721            }
1722          }
1723          #[cfg(feature = "vectord")]
1724          (l,m,1) => {
1725            let mut out = DVector::from_element(m,$default);
1726            let mut matrix_args: Vec<(Box<dyn CopyMat<$kind>>,usize)> = vec![];
1727            let mut scalar_args: Vec<(Ref<$kind>,usize)> = vec![];
1728            let mut i = 0;
1729            for arg in arguments.iter() {
1730              match &arg {
1731                Value::[<$kind:camel>](e0) => {
1732                  scalar_args.push((e0.clone(),i));
1733                  i += 1;
1734                }
1735                Value::[<Matrix $kind:camel>](e0) => {
1736                  matrix_args.push((e0.get_copyable_matrix(),i));
1737                  i += e0.shape()[0];
1738                }
1739                _ => todo!(),
1740              }
1741            }
1742            return Ok(Box::new(VerticalConcatenateVDN{scalar: scalar_args, matrix: matrix_args, out: Ref::new(out)}));
1743          }
1744          #[cfg(feature = "matrix2")]
1745          (2,2,2) => {
1746            let mut out = Matrix2::from_element($default);
1747            match &arguments[..] {
1748              // v2v2
1749              #[cfg(feature = "row_vector2")]
1750              [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: Ref::new(out)}));}
1751              _ => todo!(),
1752            }
1753          }
1754          #[cfg(feature = "matrix2x3")]
1755          (2,2,3) => {
1756            let mut out = Matrix2x3::from_element($default);
1757            match &arguments[..] {
1758              // r3r3
1759              #[cfg(feature = "row_vector3")]
1760              [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: Ref::new(out)}));}
1761              _ => todo!(),
1762            }
1763          }
1764          #[cfg(feature = "matrix3x2")]
1765          (2,3,2) => {
1766            let mut out = Matrix3x2::from_element($default);
1767            match &arguments[..] {
1768              // v2m2
1769              #[cfg(all(feature = "row_vector2", feature = "matrix2"))]
1770              [Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix2(ref e1))] => {
1771                return Ok(Box::new(VerticalConcatenateR2M2{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1772              }
1773              // m2v2
1774              #[cfg(all(feature = "matrix2", feature = "row_vector2"))]
1775              [Value::[<Matrix $kind:camel>](Matrix::Matrix2(ref e0)), Value::[<Matrix $kind:camel>](Matrix::RowVector2(ref e1))] => {
1776                return Ok(Box::new(VerticalConcatenateM2R2{e0: e0.clone(), e1: e1.clone(), out: Ref::new(out)}));
1777              }
1778              _ => todo!(),
1779            }
1780            
1781          }
1782          #[cfg(feature = "matrix3")]
1783          (2,3,3) => {
1784            let mut out = Matrix3::from_element($default);
1785            match &arguments[..] {
1786              // v3m3x2
1787              #[cfg(all(feature = "row_vector3", feature = "matrix2x3"))]
1788              [Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::Matrix2x3(ref e1))] => {
1789                return Ok(Box::new(VerticalConcatenateR3M2x3 { e0: e0.clone(), e1: e1.clone(), out: Ref::new(out) }));
1790              }
1791              // m3x2v3
1792              #[cfg(all(feature = "matrix2x3", feature = "row_vector3"))]
1793              [Value::[<Matrix $kind:camel>](Matrix::Matrix2x3(ref e0)), Value::[<Matrix $kind:camel>](Matrix::RowVector3(ref e1))] => {
1794                return Ok(Box::new(VerticalConcatenateM2x3R3 { e0: e0.clone(), e1: e1.clone(), out: Ref::new(out) }));
1795              }
1796              _ => todo!(),
1797            }
1798            
1799          }
1800          #[cfg(feature = "matrix4")]
1801          (2,4,4) => {
1802            let mut out = Matrix4::from_element($default);
1803            match &arguments[..] {
1804              // r4md
1805              #[cfg(all(feature = "row_vector4", feature = "matrixd"))]
1806              [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:Ref::new(out)})),
1807              // mdr4
1808              #[cfg(all(feature = "matrixd", feature = "row_vector4"))]
1809              [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:Ref::new(out)})),
1810              // mdmd
1811              #[cfg(feature = "matrixd")]
1812              [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:Ref::new(out)})),
1813              _ => todo!(),
1814            }
1815            
1816          }
1817          #[cfg(feature = "matrixd")]
1818          (2,m,n) => {
1819            let mut out = DMatrix::from_element(m,n,$default);
1820            match &arguments[..] {
1821              [Value::[<Matrix $kind:camel>](m0), Value::[<Matrix $kind:camel>](m1)] => {
1822                let e0 = m0.get_copyable_matrix();
1823                let e1 = m1.get_copyable_matrix();
1824                Ok(Box::new(VerticalConcatenateTwoArgs{e0, e1, out: Ref::new(out)}))
1825              }
1826              _ => todo!(),
1827            }            
1828          }
1829          #[cfg(feature = "matrix3x2")]
1830          (3,3,2) => {
1831            let mut out = Matrix3x2::from_element($default);
1832            match &arguments[..] {
1833              // r2r2r2
1834              #[cfg(feature = "row_vector2")]
1835              [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:Ref::new(out)})),
1836              _ => todo!(),
1837            }
1838          }
1839          #[cfg(feature = "matrix3")]
1840          (3,3,3) => {
1841            let mut out = Matrix3::from_element($default);
1842            match &arguments[..] {
1843              // r3r3r3
1844              #[cfg(feature = "row_vector3")]
1845              [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:Ref::new(out)})),
1846              _ => todo!(),
1847            }
1848          }
1849          #[cfg(feature = "matrix4")]
1850          (3,4,4) => {
1851            let mut out = Matrix4::from_element($default);
1852            match &arguments[..] {
1853              // r4r4md
1854              #[cfg(all(feature = "row_vector4", feature = "matrixd"))]
1855              [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:Ref::new(out)})),
1856              // r4mdr4
1857              #[cfg(all(feature = "row_vector4", feature = "matrixd"))]
1858              [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:Ref::new(out)})),
1859              // mdr4r4
1860              #[cfg(all(feature = "row_vector4", feature = "matrixd"))]
1861              [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:Ref::new(out)})),
1862              _ => todo!(),
1863            }
1864          }
1865          #[cfg(feature = "matrixd")]
1866          (3,m,n) => {
1867            let mut out = DMatrix::from_element(m,n,$default);
1868            match &arguments[..] {
1869              [Value::[<Matrix $kind:camel>](m0),Value::[<Matrix $kind:camel>](m1),Value::[<Matrix $kind:camel>](m2)] => {
1870                let e0 = m0.get_copyable_matrix();
1871                let e1 = m1.get_copyable_matrix();
1872                let e2 = m2.get_copyable_matrix();
1873                Ok(Box::new(VerticalConcatenateThreeArgs{e0,e1,e2,out:Ref::new(out)}))
1874              }   
1875              _ => todo!(),
1876            }
1877          }
1878          #[cfg(feature = "matrix4")]
1879          (4,4,4) => {
1880            let mut out = Matrix4::from_element($default);
1881            match &arguments[..] {
1882              // r4r4r4r4
1883              #[cfg(feature = "row_vector4")]
1884              [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:Ref::new(out)})),
1885              _ => todo!(),
1886            }
1887          }
1888          #[cfg(feature = "matrixd")]
1889          (4,m,n) => {
1890            let mut out = DMatrix::from_element(m,n,$default);
1891            match &arguments[..] {
1892              [Value::[<Matrix $kind:camel>](m0),Value::[<Matrix $kind:camel>](m1),Value::[<Matrix $kind:camel>](m2),Value::[<Matrix $kind:camel>](m3)] => {
1893                let e0 = m0.get_copyable_matrix();
1894                let e1 = m1.get_copyable_matrix();
1895                let e2 = m2.get_copyable_matrix();
1896                let e3 = m3.get_copyable_matrix();
1897                Ok(Box::new(VerticalConcatenateFourArgs{e0,e1,e2,e3,out:Ref::new(out)}))
1898              }   
1899              _ => todo!(),
1900            }
1901          }
1902          #[cfg(feature = "matrixd")]
1903          (l,m,n) => {
1904            let mut out = DMatrix::from_element(m,n,$default);
1905            let mut args = vec![];
1906            for arg in arguments {
1907              match arg {
1908                Value::[<Matrix $kind:camel>](m0) => {
1909                  let e0 = m0.get_copyable_matrix();
1910                  args.push(e0);
1911                }
1912                _ => todo!(),
1913              }
1914            }
1915            Ok(Box::new(VerticalConcatenateNArgs{e0: args, out:Ref::new(out)}))
1916          }
1917          _ => {return Err(MechError2::new(
1918                UnhandledFunctionArgumentKindVarg { arg: arguments.iter().map(|x| x.kind()).collect(), fxn_name: "matrix/vertcat".to_string() },
1919                None
1920              ).with_compiler_loc()
1921            );
1922          }
1923        }
1924  }}}}}
1925
1926fn impl_vertcat_fxn(arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
1927
1928  let kinds: Vec<ValueKind> = arguments.iter().map(|x| x.kind()).collect::<Vec<ValueKind>>();
1929  let target_kind = kinds[0].clone();
1930
1931  #[cfg(feature = "f64")]
1932  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::F64) { return impl_vertcat_arms!(f64, arguments, f64::default()) } }
1933
1934  #[cfg(feature = "f32")]
1935  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::F32) { return impl_vertcat_arms!(f32, arguments, f32::default()) } }
1936
1937  #[cfg(feature = "u8")]
1938  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::U8)  { return impl_vertcat_arms!(u8,  arguments, u8::default()) } }
1939
1940  #[cfg(feature = "u16")]
1941  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::U16) { return impl_vertcat_arms!(u16, arguments, u16::default()) } }
1942
1943  #[cfg(feature = "u32")]
1944  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::U32) { return impl_vertcat_arms!(u32, arguments, u32::default()) } }
1945
1946  #[cfg(feature = "u64")]
1947  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::U64) { return impl_vertcat_arms!(u64, arguments, u64::default()) } }
1948
1949  #[cfg(feature = "u128")]
1950  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::U128){ return impl_vertcat_arms!(u128, arguments, u128::default()) } }
1951
1952  #[cfg(feature = "bool")]
1953  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::Bool) { return impl_vertcat_arms!(bool, arguments, bool::default()) } }
1954
1955  #[cfg(feature = "string")]
1956  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::String) { return impl_vertcat_arms!(String, arguments, String::default()) } }
1957
1958  #[cfg(feature = "rational")]
1959  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::R64) { return impl_vertcat_arms!(R64, arguments, R64::default()) } }
1960
1961  #[cfg(feature = "complex")]
1962  { if ValueKind::is_compatible(target_kind.clone(), ValueKind::C64) { return impl_vertcat_arms!(C64, arguments, C64::default()) } }
1963
1964  Err(MechError2::new(
1965      UnhandledFunctionArgumentKindVarg { arg: arguments.iter().map(|x| x.kind()).collect(), fxn_name: "matrix/vertcat".to_string() },
1966      None
1967    ).with_compiler_loc()
1968  )
1969}
1970
1971
1972pub struct MatrixVertCat {}
1973impl NativeFunctionCompiler for MatrixVertCat {
1974  fn compile(&self, arguments: &Vec<Value>) -> MResult<Box<dyn MechFunction>> {
1975    impl_vertcat_fxn(arguments)
1976  }
1977}
1978
1979register_descriptor! {
1980  FunctionCompilerDescriptor {
1981    name: "matrix/vertcat",
1982    ptr: &MatrixVertCat{},
1983  }
1984}
1985
1986#[derive(Debug, Clone)]
1987pub struct VerticalConcatenateDimensionMismatch {
1988  pub rows: usize,
1989  pub cols: usize,
1990}
1991impl MechErrorKind2 for VerticalConcatenateDimensionMismatch {
1992  fn name(&self) -> &str { "VerticalConcatenateDimensionMismatch" }
1993  fn message(&self) -> String {
1994    format!("Cannot vertically concatenate matrices/vectors with dimensions ({}, {})", self.rows, self.cols)
1995  }
1996}