gps_pvt 0.9.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +159 -3
  3. data/README.md +4 -3
  4. data/Rakefile +24 -0
  5. data/exe/gps2ubx +12 -5
  6. data/exe/gps_pvt +7 -2
  7. data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +53 -19
  8. data/ext/gps_pvt/GPS/GPS_wrap.cxx +39 -7
  9. data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +5210 -2058
  10. data/ext/gps_pvt/extconf.rb +6 -5
  11. data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +1 -1
  12. data/ext/ninja-scan-light/tool/navigation/GPS.h +6 -2
  13. data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +1 -1
  14. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +3 -1
  15. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +3 -0
  16. data/ext/ninja-scan-light/tool/navigation/RINEX.h +9 -9
  17. data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +1 -1
  18. data/ext/ninja-scan-light/tool/navigation/coordinate.h +13 -6
  19. data/ext/ninja-scan-light/tool/param/matrix.h +1020 -247
  20. data/ext/ninja-scan-light/tool/param/matrix_fixed.h +26 -0
  21. data/ext/ninja-scan-light/tool/swig/GPS.i +6 -4
  22. data/ext/ninja-scan-light/tool/swig/SylphideMath.i +139 -36
  23. data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +115 -5
  24. data/gps_pvt.gemspec +3 -1
  25. data/lib/gps_pvt/asn1/asn1.rb +888 -0
  26. data/lib/gps_pvt/asn1/asn1.y +903 -0
  27. data/lib/gps_pvt/asn1/per.rb +182 -0
  28. data/lib/gps_pvt/ntrip.rb +1 -1
  29. data/lib/gps_pvt/receiver/agps.rb +31 -0
  30. data/lib/gps_pvt/receiver/extension.rb +94 -0
  31. data/lib/gps_pvt/receiver/rtcm3.rb +6 -4
  32. data/lib/gps_pvt/receiver.rb +41 -24
  33. data/lib/gps_pvt/rtcm3.rb +24 -34
  34. data/lib/gps_pvt/supl.rb +567 -0
  35. data/lib/gps_pvt/ubx.rb +15 -0
  36. data/lib/gps_pvt/upl/LPP-V17_5_0-Release17.asn +6441 -0
  37. data/lib/gps_pvt/upl/RRLP-V17_0_0-Release17.asn +2780 -0
  38. data/lib/gps_pvt/upl/ULP-V2_0_6-20200720-D.asn +2185 -0
  39. data/lib/gps_pvt/upl/upl.json.gz +0 -0
  40. data/lib/gps_pvt/upl/upl.rb +99 -0
  41. data/lib/gps_pvt/util.rb +1 -0
  42. data/lib/gps_pvt/version.rb +1 -1
  43. metadata +41 -3
@@ -380,6 +380,32 @@ struct MatrixBuilder_Dependency<
380
380
  (MatrixViewProperty<ViewType_R>::transposed ? nR_R : nC_R)>,
381
381
  ViewType> > {};
382
382
 
383
+ template <
384
+ class T, class T_op,
385
+ class T2, class T3, class T4, class T5,
386
+ class ViewType,
387
+ int nR_L, int nC_L, class ViewType_L,
388
+ int nR_R, int nC_R, class ViewType_R,
389
+ bool horizontal_R>
390
+ struct MatrixBuilder_Dependency<
391
+ Matrix_Frozen<
392
+ T,
393
+ Array2D_Operator<T_op, Array2D_Operator_Stack<
394
+ Matrix_Frozen<T2, Array2D_Fixed<T3, nR_L, nC_L>, ViewType_L>,
395
+ Matrix_Frozen<T4, Array2D_Fixed<T5, nR_R, nC_R>, ViewType_R>,
396
+ horizontal_R> >,
397
+ ViewType> >
398
+ : public MatrixBuilder_Dependency<
399
+ Matrix_Frozen<
400
+ T,
401
+ Array2D_Fixed<
402
+ T,
403
+ (MatrixViewProperty<ViewType_L>::transposed ? nC_L : nR_L)
404
+ + (horizontal_R ? 0 : (MatrixViewProperty<ViewType_R>::transposed ? nC_R : nR_R)),
405
+ (MatrixViewProperty<ViewType_L>::transposed ? nR_L : nC_L)
406
+ + (horizontal_R ? (MatrixViewProperty<ViewType_R>::transposed ? nR_R : nC_R) : 0)>,
407
+ ViewType> > {};
408
+
383
409
  // For optimization of local temporary matrix
384
410
  template <
385
411
  template <class, class, class> class MatrixT,
@@ -1094,18 +1094,18 @@ struct GPS_User_PVT
1094
1094
  .append(inspect_str(v_key_value)).append("}").c_str());
1095
1095
  }
1096
1096
  rb_hash_foreach(v_key_value,
1097
- #if RUBY_API_VERSION < 20700
1097
+ %#if RUBY_API_VERSION_CODE < 20700
1098
1098
  // @see https://docs.ruby-lang.org/ja/latest/doc/news=2f2_7_0.html
1099
1099
  (int (*)(ANYARGS))
1100
- #endif
1100
+ %#endif
1101
1101
  arg_t::iter2, v_arg);
1102
1102
  return ST_CONTINUE;
1103
1103
  }
1104
1104
  } arg = {val};
1105
1105
  rb_hash_foreach(obj,
1106
- #if RUBY_API_VERSION < 20700
1106
+ %#if RUBY_API_VERSION_CODE < 20700
1107
1107
  (int (*)(ANYARGS))
1108
- #endif
1108
+ %#endif
1109
1109
  arg_t::iter1, reinterpret_cast<VALUE>(&arg));
1110
1110
  return SWIG_OK;
1111
1111
  }
@@ -1169,6 +1169,7 @@ struct GPS_Measurement {
1169
1169
  L1_RANGE_RATE_SIGMA,
1170
1170
  L1_SIGNAL_STRENGTH_dBHz,
1171
1171
  L1_LOCK_SEC,
1172
+ L1_CARRIER_PHASE_AMBIGUITY_SCALE,
1172
1173
  L1_FREQUENCY,
1173
1174
  #define make_entry(key) L2CM_ ## key, L2CL_ ## key
1174
1175
  #define make_entry2(key) make_entry(key), make_entry(key ## _SIGMA)
@@ -1178,6 +1179,7 @@ struct GPS_Measurement {
1178
1179
  make_entry2(RANGE_RATE),
1179
1180
  make_entry(SIGNAL_STRENGTH_dBHz),
1180
1181
  make_entry(LOCK_SEC),
1182
+ make_entry(CARRIER_PHASE_AMBIGUITY_SCALE),
1181
1183
  #undef make_entry2
1182
1184
  #undef make_entry
1183
1185
  ITEMS_PREDEFINED,
@@ -123,16 +123,16 @@ class Complex;
123
123
  typedef Complex<T> value_type;
124
124
  static int asval(VALUE obj, value_type *v) {
125
125
  if(RB_TYPE_P(obj, T_COMPLEX)){
126
- #if RUBY_API_VERSION_CODE < 20600
126
+ %#if RUBY_API_VERSION_CODE < 20600
127
127
  static const ID id_r(rb_intern("real")), id_i(rb_intern("imag"));
128
128
  int res = swig::asval(rb_funcall(obj, id_r, 0), &(v->real()));
129
129
  if(!SWIG_IsOK(res)){return res;}
130
130
  return swig::asval(rb_funcall(obj, id_i, 0), &(v->imaginary()));
131
- #else
131
+ %#else
132
132
  int res = swig::asval(rb_complex_real(obj), &(v->real()));
133
133
  if(!SWIG_IsOK(res)){return res;}
134
134
  return swig::asval(rb_complex_imag(obj), &(v->imaginary()));
135
- #endif
135
+ %#endif
136
136
  }else{
137
137
  v->imaginary() = T(0);
138
138
  return swig::asval(obj, &(v->real()));
@@ -148,14 +148,14 @@ class Complex;
148
148
  template <class T> struct traits_check< Complex<T>, value_category> {
149
149
  static bool check(VALUE obj) {
150
150
  if(RB_TYPE_P(obj, T_COMPLEX)){
151
- #if RUBY_API_VERSION_CODE < 20600
151
+ %#if RUBY_API_VERSION_CODE < 20600
152
152
  static const ID id_r(rb_intern("real")), id_i(rb_intern("imag"));
153
153
  return swig::check<T>(rb_funcall(obj, id_r, 0))
154
154
  && swig::check<T>(rb_funcall(obj, id_i, 0));
155
- #else
155
+ %#else
156
156
  return swig::check<T>(rb_complex_real(obj))
157
157
  && swig::check<T>(rb_complex_imag(obj));
158
- #endif
158
+ %#endif
159
159
  }else{
160
160
  return swig::check<T>(obj);
161
161
  }
@@ -345,12 +345,6 @@ struct MatrixViewFilter : public BaseView {
345
345
  res.view().partial(new_rows, new_columns, row_offset, column_offset);
346
346
  return res;
347
347
  }
348
- template <class T, class Array2D_Type, class ViewType>
349
- static Matrix_Frozen<T, Array2D_Type, self_t> partial(
350
- const Matrix_Frozen<T, Array2D_Type, ViewType> &orig,
351
- const unsigned int &new_rows, const unsigned int &new_columns) {
352
- return partial(orig, new_rows, new_columns, 0, 0);
353
- }
354
348
 
355
349
  template<class CharT, class Traits>
356
350
  friend std::basic_ostream<CharT, Traits> &operator<<(
@@ -412,17 +406,27 @@ class Matrix_Frozen {
412
406
  template <class T2, class Array2D_Type2, class ViewType2>
413
407
  bool operator==(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const noexcept;
414
408
  // bool operator!= // automatically defined
415
-
409
+
416
410
  bool isSquare() const noexcept;
417
411
  bool isDiagonal() const noexcept;
412
+ bool isLowerTriangular() const noexcept;
413
+ bool isUpperTriangular() const noexcept;
418
414
  bool isSymmetric() const noexcept;
415
+ bool isHermitian() const noexcept;
416
+ bool isSkewSymmetric() const noexcept;
417
+ bool isNormal() const noexcept;
418
+ bool isOrthogonal() const noexcept;
419
+ bool isUnitary() const noexcept;
419
420
 
420
- T trace(const bool &do_check = true) const;
421
+ T trace() const;
421
422
  T sum() const noexcept;
422
423
 
423
424
  // bool isLU() const noexcept
424
425
 
425
- T determinant(const bool &do_check = true) const;
426
+ T determinant() const;
427
+ unsigned int rank() const;
428
+ T cofactor(
429
+ const unsigned int &row, const unsigned int &column) const;
426
430
  };
427
431
 
428
432
  template <class T, class Array2D_Type, class ViewType = MatrixViewBase<> >
@@ -470,6 +474,11 @@ typedef MatrixViewTranspose<MatrixViewSizeVariable<MatrixViewOffset<MatrixViewBa
470
474
 
471
475
  %{
472
476
  struct MatrixUtil {
477
+ struct each_break_t {
478
+ unsigned int r, c;
479
+ each_break_t(const unsigned int &row, const unsigned int &column)
480
+ : r(row), c(column) {}
481
+ };
473
482
  enum each_which_t {
474
483
  EACH_ALL,
475
484
  EACH_DIAGONAL,
@@ -478,6 +487,7 @@ struct MatrixUtil {
478
487
  EACH_UPPER,
479
488
  EACH_STRICT_LOWER,
480
489
  EACH_STRICT_UPPER,
490
+ EACH_UNKNOWN,
481
491
  };
482
492
  template <class T,
483
493
  class Array2D_Type, class ViewType,
@@ -488,7 +498,7 @@ struct MatrixUtil {
488
498
  const T &src_elm, T *dst_elm,
489
499
  const unsigned int &i, const unsigned int &j),
490
500
  const each_which_t &each_which = EACH_ALL,
491
- Matrix<T, Array2D_Type2, ViewType2> *dst = NULL){
501
+ Matrix<T, Array2D_Type2, ViewType2> *dst = NULL) {
492
502
  unsigned int i_max(src.rows()), j_max(src.columns());
493
503
  switch(each_which){
494
504
  case EACH_DIAGONAL:
@@ -544,10 +554,8 @@ struct MatrixUtil {
544
554
  }
545
555
  }
546
556
  #if defined(SWIGRUBY)
547
- static const each_which_t &sym2each_which(const VALUE &value){
548
- if(!RB_TYPE_P(value, T_SYMBOL)){
549
- std::invalid_argument("Symbol is required");
550
- }
557
+ static each_which_t sym2each_which(const VALUE &value){
558
+ if(!RB_TYPE_P(value, T_SYMBOL)){return EACH_UNKNOWN;}
551
559
  static const struct {
552
560
  VALUE sym;
553
561
  each_which_t which;
@@ -564,9 +572,7 @@ struct MatrixUtil {
564
572
  while(value != cmp[i].sym){
565
573
  if(++i >= (sizeof(cmp) / sizeof(cmp[0]))){break;}
566
574
  }
567
- if(i >= (sizeof(cmp) / sizeof(cmp[0]))){
568
- std::invalid_argument("Unknown enumerate direction");
569
- }
575
+ if(i >= (sizeof(cmp) / sizeof(cmp[0]))){return EACH_UNKNOWN;}
570
576
  return cmp[i].which;
571
577
  }
572
578
  #endif
@@ -671,6 +677,8 @@ struct MatrixUtil {
671
677
  %catches(std::out_of_range) rowVector;
672
678
  %catches(std::out_of_range) columnVector;
673
679
  %catches(std::logic_error, std::runtime_error) determinant;
680
+ %catches(std::logic_error) rank;
681
+ %catches(std::logic_error, std::runtime_error) cofactor;
674
682
 
675
683
  T __getitem__(const unsigned int &row, const unsigned int &column) const {
676
684
  return ($self)->operator()(row, column);
@@ -731,6 +739,17 @@ struct MatrixUtil {
731
739
  return (Matrix<T, Array2D_Dense<T> >)(($self)->operator-(scalar));
732
740
  }
733
741
 
742
+ #ifdef SWIGRUBY
743
+ %alias entrywise_product "hadamard_product";
744
+ #endif
745
+ %catches(std::invalid_argument) entrywise_product;
746
+ template <class T2, class Array2D_Type2, class ViewType2>
747
+ Matrix<T, Array2D_Dense<T> > entrywise_product(
748
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix) const {
749
+ return (Matrix<T, Array2D_Dense<T> >)(($self)->entrywise_product(matrix));
750
+ }
751
+ INSTANTIATE_MATRIX_FUNC(entrywise_product, entrywise_product);
752
+
734
753
  template <class T2, class Array2D_Type2, class ViewType2>
735
754
  Matrix<T, Array2D_Dense<T> > operator*(
736
755
  const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix)
@@ -738,6 +757,18 @@ struct MatrixUtil {
738
757
  return (Matrix<T, Array2D_Dense<T> >)(($self)->operator*(matrix));
739
758
  }
740
759
  INSTANTIATE_MATRIX_FUNC(operator*, __mul__);
760
+
761
+ // TODO __pow__ for **
762
+ // TODO __pos__ for +@
763
+
764
+ Matrix<T, Array2D_Dense<T> > first_minor(
765
+ const unsigned int &row,
766
+ const unsigned int &column) const noexcept {
767
+ return (Matrix<T, Array2D_Dense<T> >)(($self)->matrix_for_minor(row, column));
768
+ }
769
+ Matrix<T, Array2D_Dense<T> > adjugate() const {
770
+ return (Matrix<T, Array2D_Dense<T> >)(($self)->adjugate());
771
+ }
741
772
 
742
773
  %typemap(in,numinputs=0)
743
774
  Matrix<T, Array2D_Dense<T> > &output_L (Matrix<T, Array2D_Dense<T> > temp),
@@ -816,16 +847,33 @@ struct MatrixUtil {
816
847
  s << $self->inspect();
817
848
  return s.str();
818
849
  }
850
+
851
+ /* The followings are better to be implemented in Ruby
852
+ * combine, hstack, vstack (due to their arguments are variable)
853
+ */
819
854
 
820
855
  #ifdef SWIGRUBY
821
856
  %rename("square?") isSquare;
822
857
  %rename("diagonal?") isDiagonal;
858
+ %rename("lower_triangular?") isLowerTriangular;
859
+ %rename("upper_triangular?") isUpperTriangular;
823
860
  %rename("symmetric?") isSymmetric;
861
+ %rename("hermitian?") isHermitian;
862
+ %rename("skew_symmetric?") isSkewSymmetric;
863
+ %alias isSkewSymmetric "antisymmetric?"
864
+ %rename("normal?") isNormal;
865
+ %rename("orthogonal?") isOrthogonal;
866
+ %rename("unitary?") isUnitary;
824
867
  %rename("different_size?") isDifferentSize;
868
+ %alias __getitem__ "element,component";
869
+ // %alias __eq__ "eql?"; // Intentionally commented out because eql? is more strict than ==
870
+ %alias rows "row_size,row_count";
871
+ %alias columns "column_size,column_count";
825
872
  %alias trace "tr";
826
873
  %alias determinant "det";
827
874
  %alias inverse "inv";
828
875
  %alias transpose "t";
876
+ %alias conjugate "conj";
829
877
  %alias lup "lup_decomposition";
830
878
  %alias ud "ud_decomposition";
831
879
  %alias qr "qr_decomposition";
@@ -833,7 +881,7 @@ struct MatrixUtil {
833
881
  %fragment(SWIG_From_frag(Matrix_Frozen_Helper<T>), "header",
834
882
  fragment=SWIG_Traits_frag(T)){
835
883
  template <bool with_index = false, bool assign = false>
836
- static inline void matrix_yield_internal(
884
+ static inline VALUE matrix_yield_internal(
837
885
  const T &src, T *dst, const unsigned int &i, const unsigned int &j){
838
886
  SWIG_Object v;
839
887
  if(with_index){
@@ -848,6 +896,7 @@ struct MatrixUtil {
848
896
  s << "Unknown input (T expected) [" << i << "," << j << "]: ";
849
897
  throw std::invalid_argument(s.str().append(inspect_str(v)));
850
898
  }
899
+ return v;
851
900
  }
852
901
  static void matrix_yield(
853
902
  const T &src, T *dst, const unsigned int &i, const unsigned int &j){
@@ -865,11 +914,17 @@ struct MatrixUtil {
865
914
  const T &src, T *dst, const unsigned int &i, const unsigned int &j){
866
915
  matrix_yield_internal<true, true>(src, dst, i, j);
867
916
  }
917
+
918
+ static void matrix_yield_check(
919
+ const T &src, T *dst, const unsigned int &i, const unsigned int &j){
920
+ VALUE res(matrix_yield_internal<false, false>(src, dst, i, j));
921
+ if(RTEST(res)){throw typename MatrixUtil::each_break_t(i, j);}
922
+ }
868
923
  static void (*matrix_each(const T *))
869
924
  (const T &, T *, const unsigned int &, const unsigned int &) {
870
925
  ID id_thisf(rb_frame_this_func()), id_callee(rb_frame_callee());
871
926
  static const ID
872
- id_map(rb_intern("map")), id_mapb(rb_intern("map!")),
927
+ id_map(rb_intern("map")), id_mapb(rb_intern("map!")),
873
928
  id_eachwi(rb_intern("each_with_index"));
874
929
  if((id_thisf == id_map) || (id_thisf == id_mapb)){
875
930
  static const ID with_index[] = {
@@ -895,14 +950,14 @@ struct MatrixUtil {
895
950
  }
896
951
  $1 = matrix_each((const T *)0);
897
952
  }
898
- %typemap(typecheck) const typename MatrixUtil::each_which_t &each_which {
899
- $1 = RB_TYPE_P($input, T_SYMBOL);
953
+ %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) const typename MatrixUtil::each_which_t each_which {
954
+ $1 = (MatrixUtil::sym2each_which($input) != MatrixUtil::EACH_UNKNOWN);
900
955
  }
901
- %typemap(in) const typename MatrixUtil::each_which_t &each_which {
902
- try{
903
- $1 = &const_cast<typename MatrixUtil::each_which_t &>(MatrixUtil::sym2each_which($input));
904
- }catch(std::invalid_argument &e){
905
- SWIG_exception(SWIG_ValueError, e.what());
956
+ %typemap(in) const typename MatrixUtil::each_which_t each_which {
957
+ $1 = MatrixUtil::sym2each_which($input);
958
+ if($1 == MatrixUtil::EACH_UNKNOWN){
959
+ SWIG_exception(SWIG_ValueError,
960
+ std::string("Unknown enumerate direction: ").append(inspect_str($1)).c_str());
906
961
  }
907
962
  }
908
963
  %catches(native_exception) each;
@@ -910,7 +965,7 @@ struct MatrixUtil {
910
965
  void (*each_func)(
911
966
  const T &src, T *dst,
912
967
  const unsigned int &i, const unsigned int &j),
913
- const typename MatrixUtil::each_which_t &each_which = MatrixUtil::EACH_ALL) const {
968
+ const typename MatrixUtil::each_which_t each_which = MatrixUtil::EACH_ALL) const {
914
969
  MatrixUtil::each(*$self, each_func, each_which);
915
970
  return *$self;
916
971
  }
@@ -921,13 +976,37 @@ struct MatrixUtil {
921
976
  void (*each_func)(
922
977
  const T &src, T *dst,
923
978
  const unsigned int &i, const unsigned int &j),
924
- const typename MatrixUtil::each_which_t &each_which = MatrixUtil::EACH_ALL) const {
979
+ const typename MatrixUtil::each_which_t each_which = MatrixUtil::EACH_ALL) const {
925
980
  Matrix<T, Array2D_Dense<T> > res($self->operator Matrix<T, Array2D_Dense<T> >());
926
981
  MatrixUtil::each(*$self, each_func, each_which, &res);
927
982
  return res;
928
983
  }
929
984
  %alias map "collect,map_with_index,collect_with_index";
930
985
 
986
+ %catches(native_exception) index;
987
+ VALUE index(
988
+ const typename MatrixUtil::each_which_t each_which = MatrixUtil::EACH_ALL) const {
989
+ try{
990
+ MatrixUtil::each(*$self, matrix_yield_check, each_which);
991
+ return Qnil;
992
+ }catch(const typename MatrixUtil::each_break_t &each_break){
993
+ return rb_ary_new_from_args(2, UINT2NUM(each_break.r), UINT2NUM(each_break.c));
994
+ }
995
+ }
996
+ %typemap(check,noblock=1) VALUE idx_selector {
997
+ if(MatrixUtil::sym2each_which($1) == MatrixUtil::EACH_UNKNOWN){
998
+ SWIG_exception(SWIG_ValueError,
999
+ std::string("Unknown enumerate direction: ").append(inspect_str($1)).c_str());
1000
+ }
1001
+ }
1002
+ VALUE index(VALUE value, VALUE idx_selector = Qnil) const {
1003
+ return rb_block_call(
1004
+ rb_current_receiver(), rb_frame_callee(),
1005
+ (RTEST(idx_selector) ? 1 : 0), &idx_selector,
1006
+ (rb_block_call_func_t)rb_equal, value);
1007
+ }
1008
+ %alias index "find_index";
1009
+
931
1010
  SWIG_Object to_a() const {
932
1011
  unsigned int i_max($self->rows()), j_max($self->columns());
933
1012
  SWIG_Object res = rb_ary_new2(i_max);
@@ -1086,7 +1165,7 @@ MAKE_TO_S(Matrix_Frozen)
1086
1165
  void (*each_func)(
1087
1166
  const T &src, T *dst,
1088
1167
  const unsigned int &i, const unsigned int &j),
1089
- const typename MatrixUtil::each_which_t &each_which = MatrixUtil::EACH_ALL){
1168
+ const typename MatrixUtil::each_which_t each_which = MatrixUtil::EACH_ALL){
1090
1169
  MatrixUtil::each(*$self, each_func, each_which, $self);
1091
1170
  }
1092
1171
  %rename("map!") map_bang;
@@ -1115,6 +1194,14 @@ MAKE_TO_S(Matrix_Frozen)
1115
1194
  return MatView_f::partial(*$self, new_rows, new_columns, row_offset, column_offset);
1116
1195
  #else
1117
1196
  return $self->partial(new_rows, new_columns, row_offset, column_offset);
1197
+ #endif
1198
+ }
1199
+ Matrix_Frozen<type, storage, view_to> partial(
1200
+ const unsigned int &new_rows, const unsigned int &new_columns) const {
1201
+ #if defined(USE_MATRIX_VIEW_FILTER)
1202
+ return MatView_f::partial(*$self, new_rows, new_columns, 0, 0);
1203
+ #else
1204
+ return $self->partial(new_rows, new_columns, 0, 0);
1118
1205
  #endif
1119
1206
  }
1120
1207
  Matrix_Frozen<type, storage, view_to> row_vector(const unsigned int &row) const {
@@ -1132,6 +1219,9 @@ MAKE_TO_S(Matrix_Frozen)
1132
1219
  #endif
1133
1220
  }
1134
1221
  };
1222
+ /* Ruby #row, #column, #row_vectors, #column_vectors are not intentionally implemented
1223
+ * because a vector is treated as a (1*n) or (n*1) matrix in C++.
1224
+ */
1135
1225
  %enddef
1136
1226
 
1137
1227
  %define INSTANTIATE_MATRIX_EIGEN2(type, ctype, storage, view)
@@ -1152,7 +1242,7 @@ MAKE_TO_S(Matrix_Frozen)
1152
1242
  void eigen(
1153
1243
  Matrix<ctype, Array2D_Dense<ctype > > &output_V,
1154
1244
  Matrix<ctype, Array2D_Dense<ctype > > &output_D) const {
1155
- typedef typename Matrix_Frozen<type, storage, view >::complex_t::m_t cmat_t;
1245
+ typedef Matrix<ctype, Array2D_Dense<ctype > > cmat_t;
1156
1246
  cmat_t VD($self->eigen());
1157
1247
  output_V = VD.partial($self->rows(), $self->rows()).copy();
1158
1248
  cmat_t D($self->rows(), $self->rows());
@@ -1308,6 +1398,19 @@ INSTANTIATE_MATRIX_EIGEN(double, Complex<double>);
1308
1398
  INSTANTIATE_MATRIX(Complex<double>, ComplexD);
1309
1399
  INSTANTIATE_MATRIX_EIGEN(Complex<double>, Complex<double>);
1310
1400
 
1401
+ %rename("tolerance=") set_tolerance;
1402
+ %rename("tolerance") get_tolerance;
1403
+ %inline %{
1404
+ double set_tolerance(const double &width){
1405
+ MatrixValue<double>::zero = width;
1406
+ MatrixValue<Complex<double> >::zero = width;
1407
+ return width;
1408
+ }
1409
+ double get_tolerance(){
1410
+ return set_tolerance(MatrixValue<double>::zero.width);
1411
+ }
1412
+ %}
1413
+
1311
1414
  #undef INSTANTIATE_MATRIX_FUNC
1312
1415
  #undef INSTANTIATE_MATRIX_TRANSPOSE
1313
1416
  #undef INSTANTIATE_MATRIX_PARTIAL
@@ -6,6 +6,8 @@ require 'SylphideMath.so'
6
6
  require 'matrix'
7
7
 
8
8
  shared_examples 'Matrix' do
9
+ let!(:tolerance){SylphideMath::tolerance}
10
+ after{SylphideMath::tolerance = tolerance}
9
11
  let(:params){{
10
12
  :rc => [8, 8],
11
13
  :acceptable_delta => 1E-10,
@@ -92,17 +94,25 @@ shared_examples 'Matrix' do
92
94
  end
93
95
 
94
96
  describe 'property' do
95
- let(:mat){{
96
- :square => proc{
97
+ let(:mat_gen){{
98
+ :square => proc{|r| # example: [[1, 3, 6], [2, 5, 8], [4, 7, 9]]
97
99
  k = 0
98
- mat_type::new(params[:rc][0], params[:rc][0]){|i, j| k += 1}
99
- }.call,
100
+ res = mat_type::new(r, r)
101
+ (r * 2 - 1).times{|ij|
102
+ (([ij - r + 1, 0].max)..([ij, r - 1].min)).each{|i| res[ij - i, i] = (k += 1)}
103
+ }
104
+ res
105
+ }
106
+ }}
107
+ let(:mat){{
108
+ :square => mat_gen[:square].call(params[:rc][0]),
100
109
  :not_square => proc{
101
110
  k = 0
102
111
  mat_type::new(params[:rc][0], params[:rc][0] * 2){|i, j| k += 1}
103
112
  }.call,
104
113
  :diagonal => mat_type::new(params[:rc][0], params[:rc][0]){|i, j| i == j ? 1 : 0},
105
114
  :symmetric => mat_type::new(params[:rc][0], params[:rc][0]){|i, j| i + j},
115
+ :unit => mat_type::I(params[:rc][0]),
106
116
  }}
107
117
  describe 'is checked with' do
108
118
  it 'square?' do
@@ -117,12 +127,52 @@ shared_examples 'Matrix' do
117
127
  expect(mat[:diagonal].diagonal?) .to eq(true)
118
128
  expect(mat[:symmetric].diagonal?) .to eq(false)
119
129
  end
130
+ it 'lower_triangular?' do
131
+ expect(mat[:square].lower_triangular?) .to eq(false)
132
+ expect(mat[:not_square].lower_triangular?) .to eq(false)
133
+ expect(mat[:diagonal].lower_triangular?) .to eq(true)
134
+ expect(mat[:symmetric].lower_triangular?) .to eq(false)
135
+ end
136
+ it 'upper_triangular?' do
137
+ expect(mat[:square].upper_triangular?) .to eq(false)
138
+ expect(mat[:not_square].upper_triangular?) .to eq(false)
139
+ expect(mat[:diagonal].upper_triangular?) .to eq(true)
140
+ expect(mat[:symmetric].upper_triangular?) .to eq(false)
141
+ end
120
142
  it 'symmetric?' do
121
143
  expect(mat[:square].symmetric?) .to eq(false)
122
144
  expect(mat[:not_square].symmetric?) .to eq(false)
123
145
  expect(mat[:diagonal].symmetric?) .to eq(true)
124
146
  expect(mat[:symmetric].symmetric?) .to eq(true)
125
147
  end
148
+ it 'hermitian?' do
149
+ expect(mat[:square].hermitian?) .to eq(false)
150
+ expect(mat[:not_square].hermitian?) .to eq(false)
151
+ expect(mat[:diagonal].hermitian?) .to eq(true)
152
+ expect(mat[:symmetric].hermitian?) .to eq(true)
153
+ end
154
+ it 'skew_symmetric?' do
155
+ expect(mat[:square].skew_symmetric?) .to eq(false)
156
+ expect(mat[:not_square].skew_symmetric?) .to eq(false)
157
+ expect(mat[:diagonal].skew_symmetric?) .to eq(true)
158
+ expect(mat[:symmetric].skew_symmetric?) .to eq(false)
159
+ end
160
+ it 'normal?' do
161
+ expect(mat[:square].normal?) .to eq(false)
162
+ expect(mat[:not_square].normal?) .to eq(false)
163
+ expect(mat[:diagonal].normal?) .to eq(true)
164
+ expect(mat[:symmetric].normal?) .to eq(true)
165
+ end
166
+ it 'orthogonal?' do
167
+ expect(mat[:square].orthogonal?) .to eq(false)
168
+ expect(mat[:not_square].orthogonal?).to eq(false)
169
+ expect(mat[:unit].orthogonal?) .to eq(true)
170
+ end
171
+ it 'unitary?' do
172
+ expect(mat[:square].unitary?) .to eq(false)
173
+ expect(mat[:not_square].unitary?) .to eq(false)
174
+ expect(mat[:unit].unitary?) .to eq(true)
175
+ end
126
176
  it 'different_size?' do
127
177
  mat.keys.combination(2).each{|mat1, mat2|
128
178
  expect(mat[mat1].different_size?(mat[mat2])).to eq([mat1, mat2].include?(:not_square))
@@ -142,10 +192,40 @@ shared_examples 'Matrix' do
142
192
  end
143
193
  it 'determinant, det' do
144
194
  [:determinant, :det].each{|f|
145
- #expect(mat[:square].send(f)).to eq(Matrix[*mat[:square].to_a].det)
195
+ expect(mat[:square].send(f)).to eq(Matrix[*mat[:square].to_a].det)
146
196
  expect{mat[:not_square].send(f)}.to raise_error(RuntimeError)
147
197
  }
148
198
  end
199
+ it 'rank' do
200
+ (5..8).each{|n|
201
+ orig = mat_gen[:square].call(n)
202
+ expect(orig.rank).to eq(Matrix[*orig.to_a].rank)
203
+ }
204
+ expect(mat[:symmetric].rank).to eq(Matrix[*mat[:symmetric].to_a].rank)
205
+ expect{mat[:not_square].rank}.to raise_error(RuntimeError)
206
+ end
207
+ it 'cofactor' do
208
+ SylphideMath::tolerance = 1E-10
209
+ (5..8).each{|n|
210
+ orig = mat_gen[:square].call(n)
211
+ cmp = Matrix[*orig.to_a]
212
+ orig.rows.times{|i|
213
+ orig.columns.times{|j|
214
+ a, b = [orig, cmp].collect{|item| item.cofactor(i, j)} #rescue next
215
+ expect((a - b).abs).to be < params[:acceptable_delta]
216
+ }
217
+ }
218
+ }
219
+ end
220
+ it 'adjugate' do
221
+ SylphideMath::tolerance = 1E-10
222
+ (5..8).each{|n|
223
+ orig = mat_gen[:square].call(n)
224
+ (Matrix[*orig.adjugate.to_a] - Matrix[*orig.to_a].adjugate).each{|v|
225
+ expect(v.abs).to be < params[:acceptable_delta]
226
+ }
227
+ }
228
+ end
149
229
  end
150
230
  end
151
231
 
@@ -257,6 +337,8 @@ shared_examples 'Matrix' do
257
337
  expect(mat.adjoint.to_a).to eq(Matrix[*compare_with].conj.t.to_a)
258
338
  end
259
339
  it 'supports submatrix with partial' do
340
+ expect(mat.partial(params[:rc][0] - 1, params[:rc][1] - 1).to_a) \
341
+ .to eq(Matrix[*compare_with[0..-2].collect{|values| values[0..-2]}].to_a)
260
342
  expect(mat.partial(params[:rc][0] - 1, params[:rc][1] - 1, 1, 1).to_a) \
261
343
  .to eq(Matrix[*compare_with[1..-1].collect{|values| values[1..-1]}].to_a)
262
344
  end
@@ -280,6 +362,14 @@ shared_examples 'Matrix' do
280
362
  }
281
363
  }
282
364
  end
365
+ it 'generates minor matrix with first_minor' do
366
+ params[:rc][0].times{|i|
367
+ params[:rc][1].times{|j|
368
+ expect(mat.first_minor(i, j).to_a) \
369
+ .to eq(Matrix[*compare_with].first_minor(i, j).to_a)
370
+ }
371
+ }
372
+ end
283
373
  end
284
374
 
285
375
  describe 'iterator' do
@@ -310,6 +400,19 @@ shared_examples 'Matrix' do
310
400
  }
311
401
  }
312
402
  end
403
+ it 'supports index, find_index' do
404
+ cnd = proc{|v| v.abs >= 0.5}
405
+ [:index, :find_index].each{|func|
406
+ opt.each{|k, indices|
407
+ expect(mat.send(*[func, k].compact, &cnd)).to eq(
408
+ indices.select{|i, j| cnd.call(compare_with[i][j])}.first)
409
+ indices.each{|i, j|
410
+ expect(mat.send(*[func, compare_with[i][j], k].compact)).to eq([i, j])
411
+ }
412
+ expect(mat.send(*[func, 1, k].compact)).to be(nil)
413
+ }
414
+ }
415
+ end
313
416
  it 'supports map, collect, map_with_index, collect_with_index' do
314
417
  [:map, :collect, :map_with_index, :collect_with_index].each{|func|
315
418
  opt.each{|k, indices|
@@ -398,6 +501,13 @@ shared_examples 'Matrix' do
398
501
  expect{mat[2] * mat[3]}.to raise_error(ArgumentError)
399
502
  expect((mat[2] * mat[3].t).to_a).to eq((Matrix[*compare_with[2]] * Matrix[*compare_with[3]].t).to_a)
400
503
  end
504
+ it 'have entrywise_product(mat), a.k.a. .*(mat)' do
505
+ [:entrywise_product, :hadamard_product].each{|func|
506
+ [[0, 1], [2, 3]].each{|i, j|
507
+ expect((mat[i].send(func, mat[j])).to_a).to eq((Matrix[*compare_with[i]].send(func, Matrix[*compare_with[j]])).to_a)
508
+ }
509
+ } if Gem::Version::create(RUBY_VERSION) >= Gem::Version::create("2.5.0")
510
+ end
401
511
  it 'have /(scalar)' do
402
512
  expect((mat[0] / 2).to_a).to eq((Matrix[*compare_with[0]] / 2).to_a)
403
513
  expect((mat[2] / 2).to_a).to eq((Matrix[*compare_with[2]] / 2).to_a)
data/gps_pvt.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
  spec.metadata["source_code_uri"] = spec.homepage
20
- #spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
20
+ #spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/-/CHANGELOG.md"
21
21
 
22
22
  spec.extensions = ["ext/gps_pvt/extconf.rb"]
23
23
 
@@ -63,6 +63,8 @@ Gem::Specification.new do |spec|
63
63
  spec.add_development_dependency "rake-compiler"
64
64
  spec.add_development_dependency "rspec", "~> 3.0"
65
65
  spec.add_development_dependency "matrix" if GPS_PVT::version_compare(RUBY_VERSION, "3.1") >= 0
66
+ spec.add_development_dependency "racc"
67
+ spec.add_development_dependency "github_changelog_generator" unless ((Gem::Platform.local.os =~ /mingw/) && (GPS_PVT::version_compare(RUBY_VERSION, "3.1") >= 0))
66
68
 
67
69
  # For more information and examples about making a new gem, checkout our
68
70
  # guide at: https://bundler.io/guides/creating_gem.html