umappp 0.2.1 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d88fcf9fcf8f61232a094afbf62a7aa421c564e644a854bd2efc1ba94dd1ab02
4
- data.tar.gz: a92531b8da81479a4844ec5f5073423eefdf3fb9d32bed6f7cbe867771116087
3
+ metadata.gz: f50fd5a0af819b29f30afbf2cad8e059c679b9691b2c42a106724d7c9cb313e3
4
+ data.tar.gz: d4f583765cc15aec1f4102d35699208cac47df086cea14fd485eb99c15b8a027
5
5
  SHA512:
6
- metadata.gz: c56ce6be1fe5d9f296b512121be5e94cd844d2ea76ec75ad8e3224ace4023a45146da5cfe4fa779d557c99afbce85a22b951cd2b21a8b1f4f151c5911b13d12a
7
- data.tar.gz: 21be7903f3aa0f03c0a60bf011415f115501e6741a94791465a6e25789ed2c411aed87042b11eeb15aa8ac43d39dff9000a30a7c79cdd0de1b310bd7f5b30044
6
+ metadata.gz: 9a505cbe40f4b059dc2af714759fe1cbcda70cd132fe08fe1e463a20e93c3fa3b8981152116b94e2f5e3ff1aa344959d0f815368c1838cef17cdcdfb6288dce6
7
+ data.tar.gz: 7798c54f1a7bd98fb3decc32ef779e945b41d3332bd2d3b5a0c58570c084840a2da5c0af57b185d4c57b93d3b49506cb65ac86d5ccb48ba9570ba013b4de71ef
data/README.md CHANGED
@@ -27,16 +27,22 @@ gem install umappp
27
27
  This Gem provides the module `Umappp` and its singular method `Umappp.run()`. The first argument of `Umappp.run()` is a two-dimensional Ruby array or a two-dimensional Numo array. [Numo](https://github.com/ruby-numo/numo-narray) is a library for performing N-dimensional array computing like NumPy. The argument is converted to `Numo::SFloat`. SFloat is a single precision floating point number type of Numo::NArray.
28
28
 
29
29
  ```ruby
30
- # The embedding is two-dimensional Ruby array or Numo array
31
- # Returns Numo::SFloat
32
- r = Umappp.run(embedding)
30
+ # Original high-dimensional data as two-dimensional Ruby array or Numo array
31
+ data = Numo::SFloat.new(10, 784).rand # e.g. 10 images with 784 features
32
+
33
+ # Returns low-dimensional embedding as Numo::SFloat
34
+ embedding = Umappp.run(data)
33
35
 
34
36
  # Run with parameters
35
- r = Umappp.run(pixels, num_threads: 8, a: 1.8956, b: 0.8006)
37
+ embedding = Umappp.run(data, num_threads: 8, a: 1.8956, b: 0.8006)
36
38
  ```
37
39
 
38
40
  Available parameters and their default values
39
41
 
42
+ (The defaults are obtained from the underlying C++ Umappp
43
+ library via `Umappp.default_parameters` and may change when
44
+ the bundled Umappp version is updated.)
45
+
40
46
  | parameters | default value |
41
47
  | -------------------- | ---------------------------------- |
42
48
  | method | :annoy (another option is :vptree) |
@@ -57,11 +63,15 @@ Available parameters and their default values
57
63
  | seed | 1234567890 |
58
64
  | num_threads | 1 (OpenMP required) |
59
65
 
66
+ For the `initialize` parameter, this gem currently accepts the
67
+ symbols `:spectral`, `:spectral_only`, `:random` and `:none`,
68
+ which are mapped to `Umappp::InitMethod` values internally.
69
+
60
70
  ## Development
61
71
 
62
72
  ```
63
73
  git clone https://github.com/kojix2/ruby-umappp
64
- cd umap
74
+ cd ruby-umappp
65
75
  bundle exec rake compile
66
76
  bundle exec rake test
67
77
  ```
data/ext/umappp/numo.hpp CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Numo.hpp v0.2.0
2
+ * Numo.hpp v0.2.1
3
3
  * https://github.com/ankane/numo.hpp
4
4
  * BSD-2-Clause License
5
5
  */
@@ -449,18 +449,19 @@ private:
449
449
  namespace Rice::detail {
450
450
 
451
451
  template<>
452
- struct Type<numo::NArray>
453
- {
452
+ struct Type<numo::NArray> {
454
453
  static bool verify() { return true; }
455
454
  };
456
455
 
457
456
  template<>
458
- class From_Ruby<numo::NArray>
459
- {
457
+ class From_Ruby<numo::NArray> {
460
458
  public:
459
+ From_Ruby() = default;
460
+
461
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
462
+
461
463
  Convertible is_convertible(VALUE value) {
462
- switch (rb_type(value))
463
- {
464
+ switch (rb_type(value)) {
464
465
  case RUBY_T_DATA:
465
466
  return Data_Type<numo::NArray>::is_descendant(value) ? Convertible::Exact : Convertible::None;
466
467
  case RUBY_T_ARRAY:
@@ -473,30 +474,40 @@ public:
473
474
  numo::NArray convert(VALUE x) {
474
475
  return numo::NArray(x);
475
476
  }
477
+
478
+ private:
479
+ Arg* arg_ = nullptr;
476
480
  };
477
481
 
478
482
  template<>
479
- class To_Ruby<numo::NArray>
480
- {
483
+ class To_Ruby<numo::NArray> {
481
484
  public:
485
+ To_Ruby() = default;
486
+
487
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
488
+
482
489
  VALUE convert(const numo::NArray& x) {
483
490
  return x.value();
484
491
  }
492
+
493
+ private:
494
+ Arg* arg_ = nullptr;
485
495
  };
486
496
 
487
497
  template<>
488
- struct Type<numo::SFloat>
489
- {
498
+ struct Type<numo::SFloat> {
490
499
  static bool verify() { return true; }
491
500
  };
492
501
 
493
502
  template<>
494
- class From_Ruby<numo::SFloat>
495
- {
503
+ class From_Ruby<numo::SFloat> {
496
504
  public:
505
+ From_Ruby() = default;
506
+
507
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
508
+
497
509
  Convertible is_convertible(VALUE value) {
498
- switch (rb_type(value))
499
- {
510
+ switch (rb_type(value)) {
500
511
  case RUBY_T_DATA:
501
512
  return Data_Type<numo::SFloat>::is_descendant(value) ? Convertible::Exact : Convertible::None;
502
513
  case RUBY_T_ARRAY:
@@ -509,30 +520,40 @@ public:
509
520
  numo::SFloat convert(VALUE x) {
510
521
  return numo::SFloat(x);
511
522
  }
523
+
524
+ private:
525
+ Arg* arg_ = nullptr;
512
526
  };
513
527
 
514
528
  template<>
515
- class To_Ruby<numo::SFloat>
516
- {
529
+ class To_Ruby<numo::SFloat> {
517
530
  public:
531
+ To_Ruby() = default;
532
+
533
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
534
+
518
535
  VALUE convert(const numo::SFloat& x) {
519
536
  return x.value();
520
537
  }
538
+
539
+ private:
540
+ Arg* arg_ = nullptr;
521
541
  };
522
542
 
523
543
  template<>
524
- struct Type<numo::DFloat>
525
- {
544
+ struct Type<numo::DFloat> {
526
545
  static bool verify() { return true; }
527
546
  };
528
547
 
529
548
  template<>
530
- class From_Ruby<numo::DFloat>
531
- {
549
+ class From_Ruby<numo::DFloat> {
532
550
  public:
551
+ From_Ruby() = default;
552
+
553
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
554
+
533
555
  Convertible is_convertible(VALUE value) {
534
- switch (rb_type(value))
535
- {
556
+ switch (rb_type(value)) {
536
557
  case RUBY_T_DATA:
537
558
  return Data_Type<numo::DFloat>::is_descendant(value) ? Convertible::Exact : Convertible::None;
538
559
  case RUBY_T_ARRAY:
@@ -545,30 +566,40 @@ public:
545
566
  numo::DFloat convert(VALUE x) {
546
567
  return numo::DFloat(x);
547
568
  }
569
+
570
+ private:
571
+ Arg* arg_ = nullptr;
548
572
  };
549
573
 
550
574
  template<>
551
- class To_Ruby<numo::DFloat>
552
- {
575
+ class To_Ruby<numo::DFloat> {
553
576
  public:
577
+ To_Ruby() = default;
578
+
579
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
580
+
554
581
  VALUE convert(const numo::DFloat& x) {
555
582
  return x.value();
556
583
  }
584
+
585
+ private:
586
+ Arg* arg_ = nullptr;
557
587
  };
558
588
 
559
589
  template<>
560
- struct Type<numo::Int8>
561
- {
590
+ struct Type<numo::Int8> {
562
591
  static bool verify() { return true; }
563
592
  };
564
593
 
565
594
  template<>
566
- class From_Ruby<numo::Int8>
567
- {
595
+ class From_Ruby<numo::Int8> {
568
596
  public:
597
+ From_Ruby() = default;
598
+
599
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
600
+
569
601
  Convertible is_convertible(VALUE value) {
570
- switch (rb_type(value))
571
- {
602
+ switch (rb_type(value)) {
572
603
  case RUBY_T_DATA:
573
604
  return Data_Type<numo::Int8>::is_descendant(value) ? Convertible::Exact : Convertible::None;
574
605
  case RUBY_T_ARRAY:
@@ -581,30 +612,40 @@ public:
581
612
  numo::Int8 convert(VALUE x) {
582
613
  return numo::Int8(x);
583
614
  }
615
+
616
+ private:
617
+ Arg* arg_ = nullptr;
584
618
  };
585
619
 
586
620
  template<>
587
- class To_Ruby<numo::Int8>
588
- {
621
+ class To_Ruby<numo::Int8> {
589
622
  public:
623
+ To_Ruby() = default;
624
+
625
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
626
+
590
627
  VALUE convert(const numo::Int8& x) {
591
628
  return x.value();
592
629
  }
630
+
631
+ private:
632
+ Arg* arg_ = nullptr;
593
633
  };
594
634
 
595
635
  template<>
596
- struct Type<numo::Int16>
597
- {
636
+ struct Type<numo::Int16> {
598
637
  static bool verify() { return true; }
599
638
  };
600
639
 
601
640
  template<>
602
- class From_Ruby<numo::Int16>
603
- {
641
+ class From_Ruby<numo::Int16> {
604
642
  public:
643
+ From_Ruby() = default;
644
+
645
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
646
+
605
647
  Convertible is_convertible(VALUE value) {
606
- switch (rb_type(value))
607
- {
648
+ switch (rb_type(value)) {
608
649
  case RUBY_T_DATA:
609
650
  return Data_Type<numo::Int16>::is_descendant(value) ? Convertible::Exact : Convertible::None;
610
651
  case RUBY_T_ARRAY:
@@ -617,30 +658,40 @@ public:
617
658
  numo::Int16 convert(VALUE x) {
618
659
  return numo::Int16(x);
619
660
  }
661
+
662
+ private:
663
+ Arg* arg_ = nullptr;
620
664
  };
621
665
 
622
666
  template<>
623
- class To_Ruby<numo::Int16>
624
- {
667
+ class To_Ruby<numo::Int16> {
625
668
  public:
669
+ To_Ruby() = default;
670
+
671
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
672
+
626
673
  VALUE convert(const numo::Int16& x) {
627
674
  return x.value();
628
675
  }
676
+
677
+ private:
678
+ Arg* arg_ = nullptr;
629
679
  };
630
680
 
631
681
  template<>
632
- struct Type<numo::Int32>
633
- {
682
+ struct Type<numo::Int32> {
634
683
  static bool verify() { return true; }
635
684
  };
636
685
 
637
686
  template<>
638
- class From_Ruby<numo::Int32>
639
- {
687
+ class From_Ruby<numo::Int32> {
640
688
  public:
689
+ From_Ruby() = default;
690
+
691
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
692
+
641
693
  Convertible is_convertible(VALUE value) {
642
- switch (rb_type(value))
643
- {
694
+ switch (rb_type(value)) {
644
695
  case RUBY_T_DATA:
645
696
  return Data_Type<numo::Int32>::is_descendant(value) ? Convertible::Exact : Convertible::None;
646
697
  case RUBY_T_ARRAY:
@@ -653,30 +704,40 @@ public:
653
704
  numo::Int32 convert(VALUE x) {
654
705
  return numo::Int32(x);
655
706
  }
707
+
708
+ private:
709
+ Arg* arg_ = nullptr;
656
710
  };
657
711
 
658
712
  template<>
659
- class To_Ruby<numo::Int32>
660
- {
713
+ class To_Ruby<numo::Int32> {
661
714
  public:
715
+ To_Ruby() = default;
716
+
717
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
718
+
662
719
  VALUE convert(const numo::Int32& x) {
663
720
  return x.value();
664
721
  }
722
+
723
+ private:
724
+ Arg* arg_ = nullptr;
665
725
  };
666
726
 
667
727
  template<>
668
- struct Type<numo::Int64>
669
- {
728
+ struct Type<numo::Int64> {
670
729
  static bool verify() { return true; }
671
730
  };
672
731
 
673
732
  template<>
674
- class From_Ruby<numo::Int64>
675
- {
733
+ class From_Ruby<numo::Int64> {
676
734
  public:
735
+ From_Ruby() = default;
736
+
737
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
738
+
677
739
  Convertible is_convertible(VALUE value) {
678
- switch (rb_type(value))
679
- {
740
+ switch (rb_type(value)) {
680
741
  case RUBY_T_DATA:
681
742
  return Data_Type<numo::Int64>::is_descendant(value) ? Convertible::Exact : Convertible::None;
682
743
  case RUBY_T_ARRAY:
@@ -689,30 +750,40 @@ public:
689
750
  numo::Int64 convert(VALUE x) {
690
751
  return numo::Int64(x);
691
752
  }
753
+
754
+ private:
755
+ Arg* arg_ = nullptr;
692
756
  };
693
757
 
694
758
  template<>
695
- class To_Ruby<numo::Int64>
696
- {
759
+ class To_Ruby<numo::Int64> {
697
760
  public:
761
+ To_Ruby() = default;
762
+
763
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
764
+
698
765
  VALUE convert(const numo::Int64& x) {
699
766
  return x.value();
700
767
  }
768
+
769
+ private:
770
+ Arg* arg_ = nullptr;
701
771
  };
702
772
 
703
773
  template<>
704
- struct Type<numo::UInt8>
705
- {
774
+ struct Type<numo::UInt8> {
706
775
  static bool verify() { return true; }
707
776
  };
708
777
 
709
778
  template<>
710
- class From_Ruby<numo::UInt8>
711
- {
779
+ class From_Ruby<numo::UInt8> {
712
780
  public:
781
+ From_Ruby() = default;
782
+
783
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
784
+
713
785
  Convertible is_convertible(VALUE value) {
714
- switch (rb_type(value))
715
- {
786
+ switch (rb_type(value)) {
716
787
  case RUBY_T_DATA:
717
788
  return Data_Type<numo::UInt8>::is_descendant(value) ? Convertible::Exact : Convertible::None;
718
789
  case RUBY_T_ARRAY:
@@ -725,30 +796,40 @@ public:
725
796
  numo::UInt8 convert(VALUE x) {
726
797
  return numo::UInt8(x);
727
798
  }
799
+
800
+ private:
801
+ Arg* arg_ = nullptr;
728
802
  };
729
803
 
730
804
  template<>
731
- class To_Ruby<numo::UInt8>
732
- {
805
+ class To_Ruby<numo::UInt8> {
733
806
  public:
807
+ To_Ruby() = default;
808
+
809
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
810
+
734
811
  VALUE convert(const numo::UInt8& x) {
735
812
  return x.value();
736
813
  }
814
+
815
+ private:
816
+ Arg* arg_ = nullptr;
737
817
  };
738
818
 
739
819
  template<>
740
- struct Type<numo::UInt16>
741
- {
820
+ struct Type<numo::UInt16> {
742
821
  static bool verify() { return true; }
743
822
  };
744
823
 
745
824
  template<>
746
- class From_Ruby<numo::UInt16>
747
- {
825
+ class From_Ruby<numo::UInt16> {
748
826
  public:
827
+ From_Ruby() = default;
828
+
829
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
830
+
749
831
  Convertible is_convertible(VALUE value) {
750
- switch (rb_type(value))
751
- {
832
+ switch (rb_type(value)) {
752
833
  case RUBY_T_DATA:
753
834
  return Data_Type<numo::UInt16>::is_descendant(value) ? Convertible::Exact : Convertible::None;
754
835
  case RUBY_T_ARRAY:
@@ -761,30 +842,40 @@ public:
761
842
  numo::UInt16 convert(VALUE x) {
762
843
  return numo::UInt16(x);
763
844
  }
845
+
846
+ private:
847
+ Arg* arg_ = nullptr;
764
848
  };
765
849
 
766
850
  template<>
767
- class To_Ruby<numo::UInt16>
768
- {
851
+ class To_Ruby<numo::UInt16> {
769
852
  public:
853
+ To_Ruby() = default;
854
+
855
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
856
+
770
857
  VALUE convert(const numo::UInt16& x) {
771
858
  return x.value();
772
859
  }
860
+
861
+ private:
862
+ Arg* arg_ = nullptr;
773
863
  };
774
864
 
775
865
  template<>
776
- struct Type<numo::UInt32>
777
- {
866
+ struct Type<numo::UInt32> {
778
867
  static bool verify() { return true; }
779
868
  };
780
869
 
781
870
  template<>
782
- class From_Ruby<numo::UInt32>
783
- {
871
+ class From_Ruby<numo::UInt32> {
784
872
  public:
873
+ From_Ruby() = default;
874
+
875
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
876
+
785
877
  Convertible is_convertible(VALUE value) {
786
- switch (rb_type(value))
787
- {
878
+ switch (rb_type(value)) {
788
879
  case RUBY_T_DATA:
789
880
  return Data_Type<numo::UInt32>::is_descendant(value) ? Convertible::Exact : Convertible::None;
790
881
  case RUBY_T_ARRAY:
@@ -797,30 +888,40 @@ public:
797
888
  numo::UInt32 convert(VALUE x) {
798
889
  return numo::UInt32(x);
799
890
  }
891
+
892
+ private:
893
+ Arg* arg_ = nullptr;
800
894
  };
801
895
 
802
896
  template<>
803
- class To_Ruby<numo::UInt32>
804
- {
897
+ class To_Ruby<numo::UInt32> {
805
898
  public:
899
+ To_Ruby() = default;
900
+
901
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
902
+
806
903
  VALUE convert(const numo::UInt32& x) {
807
904
  return x.value();
808
905
  }
906
+
907
+ private:
908
+ Arg* arg_ = nullptr;
809
909
  };
810
910
 
811
911
  template<>
812
- struct Type<numo::UInt64>
813
- {
912
+ struct Type<numo::UInt64> {
814
913
  static bool verify() { return true; }
815
914
  };
816
915
 
817
916
  template<>
818
- class From_Ruby<numo::UInt64>
819
- {
917
+ class From_Ruby<numo::UInt64> {
820
918
  public:
919
+ From_Ruby() = default;
920
+
921
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
922
+
821
923
  Convertible is_convertible(VALUE value) {
822
- switch (rb_type(value))
823
- {
924
+ switch (rb_type(value)) {
824
925
  case RUBY_T_DATA:
825
926
  return Data_Type<numo::UInt64>::is_descendant(value) ? Convertible::Exact : Convertible::None;
826
927
  case RUBY_T_ARRAY:
@@ -833,30 +934,40 @@ public:
833
934
  numo::UInt64 convert(VALUE x) {
834
935
  return numo::UInt64(x);
835
936
  }
937
+
938
+ private:
939
+ Arg* arg_ = nullptr;
836
940
  };
837
941
 
838
942
  template<>
839
- class To_Ruby<numo::UInt64>
840
- {
943
+ class To_Ruby<numo::UInt64> {
841
944
  public:
945
+ To_Ruby() = default;
946
+
947
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
948
+
842
949
  VALUE convert(const numo::UInt64& x) {
843
950
  return x.value();
844
951
  }
952
+
953
+ private:
954
+ Arg* arg_ = nullptr;
845
955
  };
846
956
 
847
957
  template<>
848
- struct Type<numo::SComplex>
849
- {
958
+ struct Type<numo::SComplex> {
850
959
  static bool verify() { return true; }
851
960
  };
852
961
 
853
962
  template<>
854
- class From_Ruby<numo::SComplex>
855
- {
963
+ class From_Ruby<numo::SComplex> {
856
964
  public:
965
+ From_Ruby() = default;
966
+
967
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
968
+
857
969
  Convertible is_convertible(VALUE value) {
858
- switch (rb_type(value))
859
- {
970
+ switch (rb_type(value)) {
860
971
  case RUBY_T_DATA:
861
972
  return Data_Type<numo::SComplex>::is_descendant(value) ? Convertible::Exact : Convertible::None;
862
973
  case RUBY_T_ARRAY:
@@ -869,30 +980,40 @@ public:
869
980
  numo::SComplex convert(VALUE x) {
870
981
  return numo::SComplex(x);
871
982
  }
983
+
984
+ private:
985
+ Arg* arg_ = nullptr;
872
986
  };
873
987
 
874
988
  template<>
875
- class To_Ruby<numo::SComplex>
876
- {
989
+ class To_Ruby<numo::SComplex> {
877
990
  public:
991
+ To_Ruby() = default;
992
+
993
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
994
+
878
995
  VALUE convert(const numo::SComplex& x) {
879
996
  return x.value();
880
997
  }
998
+
999
+ private:
1000
+ Arg* arg_ = nullptr;
881
1001
  };
882
1002
 
883
1003
  template<>
884
- struct Type<numo::DComplex>
885
- {
1004
+ struct Type<numo::DComplex> {
886
1005
  static bool verify() { return true; }
887
1006
  };
888
1007
 
889
1008
  template<>
890
- class From_Ruby<numo::DComplex>
891
- {
1009
+ class From_Ruby<numo::DComplex> {
892
1010
  public:
1011
+ From_Ruby() = default;
1012
+
1013
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
1014
+
893
1015
  Convertible is_convertible(VALUE value) {
894
- switch (rb_type(value))
895
- {
1016
+ switch (rb_type(value)) {
896
1017
  case RUBY_T_DATA:
897
1018
  return Data_Type<numo::DComplex>::is_descendant(value) ? Convertible::Exact : Convertible::None;
898
1019
  case RUBY_T_ARRAY:
@@ -905,30 +1026,40 @@ public:
905
1026
  numo::DComplex convert(VALUE x) {
906
1027
  return numo::DComplex(x);
907
1028
  }
1029
+
1030
+ private:
1031
+ Arg* arg_ = nullptr;
908
1032
  };
909
1033
 
910
1034
  template<>
911
- class To_Ruby<numo::DComplex>
912
- {
1035
+ class To_Ruby<numo::DComplex> {
913
1036
  public:
1037
+ To_Ruby() = default;
1038
+
1039
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
1040
+
914
1041
  VALUE convert(const numo::DComplex& x) {
915
1042
  return x.value();
916
1043
  }
1044
+
1045
+ private:
1046
+ Arg* arg_ = nullptr;
917
1047
  };
918
1048
 
919
1049
  template<>
920
- struct Type<numo::Bit>
921
- {
1050
+ struct Type<numo::Bit> {
922
1051
  static bool verify() { return true; }
923
1052
  };
924
1053
 
925
1054
  template<>
926
- class From_Ruby<numo::Bit>
927
- {
1055
+ class From_Ruby<numo::Bit> {
928
1056
  public:
1057
+ From_Ruby() = default;
1058
+
1059
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
1060
+
929
1061
  Convertible is_convertible(VALUE value) {
930
- switch (rb_type(value))
931
- {
1062
+ switch (rb_type(value)) {
932
1063
  case RUBY_T_DATA:
933
1064
  return Data_Type<numo::Bit>::is_descendant(value) ? Convertible::Exact : Convertible::None;
934
1065
  case RUBY_T_ARRAY:
@@ -941,30 +1072,40 @@ public:
941
1072
  numo::Bit convert(VALUE x) {
942
1073
  return numo::Bit(x);
943
1074
  }
1075
+
1076
+ private:
1077
+ Arg* arg_ = nullptr;
944
1078
  };
945
1079
 
946
1080
  template<>
947
- class To_Ruby<numo::Bit>
948
- {
1081
+ class To_Ruby<numo::Bit> {
949
1082
  public:
1083
+ To_Ruby() = default;
1084
+
1085
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
1086
+
950
1087
  VALUE convert(const numo::Bit& x) {
951
1088
  return x.value();
952
1089
  }
1090
+
1091
+ private:
1092
+ Arg* arg_ = nullptr;
953
1093
  };
954
1094
 
955
1095
  template<>
956
- struct Type<numo::RObject>
957
- {
1096
+ struct Type<numo::RObject> {
958
1097
  static bool verify() { return true; }
959
1098
  };
960
1099
 
961
1100
  template<>
962
- class From_Ruby<numo::RObject>
963
- {
1101
+ class From_Ruby<numo::RObject> {
964
1102
  public:
1103
+ From_Ruby() = default;
1104
+
1105
+ explicit From_Ruby(Arg* arg) : arg_(arg) { }
1106
+
965
1107
  Convertible is_convertible(VALUE value) {
966
- switch (rb_type(value))
967
- {
1108
+ switch (rb_type(value)) {
968
1109
  case RUBY_T_DATA:
969
1110
  return Data_Type<numo::RObject>::is_descendant(value) ? Convertible::Exact : Convertible::None;
970
1111
  case RUBY_T_ARRAY:
@@ -977,15 +1118,24 @@ public:
977
1118
  numo::RObject convert(VALUE x) {
978
1119
  return numo::RObject(x);
979
1120
  }
1121
+
1122
+ private:
1123
+ Arg* arg_ = nullptr;
980
1124
  };
981
1125
 
982
1126
  template<>
983
- class To_Ruby<numo::RObject>
984
- {
1127
+ class To_Ruby<numo::RObject> {
985
1128
  public:
1129
+ To_Ruby() = default;
1130
+
1131
+ explicit To_Ruby(Arg* arg) : arg_(arg) { }
1132
+
986
1133
  VALUE convert(const numo::RObject& x) {
987
1134
  return x.value();
988
1135
  }
1136
+
1137
+ private:
1138
+ Arg* arg_ = nullptr;
989
1139
  };
990
1140
 
991
1141
  }
@@ -1,8 +1,12 @@
1
- // Uniform Manifold Approximation and Projection for Ruby
2
- // https://github.com/kojix2/ruby-umappp
1
+ /*
2
+ * Uniform Manifold Approximation and Projection for Ruby
3
+ * https://github.com/kojix2/ruby-umappp
4
+ */
3
5
 
4
6
  #include <rice/rice.hpp>
5
7
  #include <rice/stl.hpp>
8
+ #include <exception>
9
+ #include <string>
6
10
  #include "numo.hpp"
7
11
  #include "Umap.hpp"
8
12
 
@@ -11,8 +15,44 @@ typedef typename umappp::Umap<Float> Umap;
11
15
 
12
16
  using namespace Rice;
13
17
 
14
- // This function is used to view default parameters from Ruby.
18
+ // Data structure for running UMAP calculation without GVL.
19
+ struct UmapRunData
20
+ {
21
+ Umap *umap_ptr;
22
+ knncolle::Base<int, Float> *knncolle_ptr;
23
+ int ndim;
24
+ std::vector<Float> *embedding;
25
+ std::string exception_message;
26
+ bool exception_thrown = false;
27
+ };
28
+
29
+ // Callback for UMAP calculation (executed without GVL).
30
+ static void *umap_run_without_gvl(void *data)
31
+ {
32
+ UmapRunData *run_data = static_cast<UmapRunData *>(data);
33
+ try
34
+ {
35
+ auto status = run_data->umap_ptr->initialize(
36
+ run_data->knncolle_ptr,
37
+ run_data->ndim,
38
+ run_data->embedding->data());
39
+ int epoch_limit = 0;
40
+ status.run(epoch_limit);
41
+ }
42
+ catch (const std::exception &e)
43
+ {
44
+ run_data->exception_message = e.what();
45
+ run_data->exception_thrown = true;
46
+ }
47
+ catch (...)
48
+ {
49
+ run_data->exception_message = "Unknown exception occurred in UMAP calculation.";
50
+ run_data->exception_thrown = true;
51
+ }
52
+ return nullptr;
53
+ }
15
54
 
55
+ // Returns default parameters from the Umappp C++ library.
16
56
  Hash umappp_default_parameters(Object self)
17
57
  {
18
58
  Hash d;
@@ -36,8 +76,7 @@ Hash umappp_default_parameters(Object self)
36
76
  return d;
37
77
  }
38
78
 
39
- // Function to perform umap.
40
-
79
+ // Main function to perform UMAP.
41
80
  Object umappp_run(
42
81
  Object self,
43
82
  Hash params,
@@ -45,8 +84,6 @@ Object umappp_run(
45
84
  int ndim,
46
85
  int nn_method)
47
86
  {
48
- // Parameters are taken from a Ruby Hash object.
49
- // If there is key, set the value.
50
87
  if (ndim < 1)
51
88
  {
52
89
  throw std::runtime_error("ndim is less than 1");
@@ -166,16 +203,18 @@ Object umappp_run(
166
203
  umap_ptr->set_parallel_optimization(parallel_optimization);
167
204
  }
168
205
 
169
- // initialize_from_matrix
170
-
171
206
  const float *y = data.read_ptr();
172
207
  size_t *shape = data.shape();
173
208
 
174
209
  int nd = shape[1];
175
210
  int nobs = shape[0];
176
- if (nobs < 0)
211
+ if (nobs <= 0)
177
212
  {
178
- throw std::runtime_error("nobs is negative");
213
+ throw std::runtime_error("number of observations must be positive");
214
+ }
215
+ if (nd <= 0)
216
+ {
217
+ throw std::runtime_error("number of dimensions must be positive");
179
218
  }
180
219
 
181
220
  std::unique_ptr<knncolle::Base<int, Float>> knncolle_ptr;
@@ -187,16 +226,31 @@ Object umappp_run(
187
226
  {
188
227
  knncolle_ptr.reset(new knncolle::KmknnEuclidean<int, Float>(nd, nobs, y));
189
228
  }
229
+ else
230
+ {
231
+ throw std::runtime_error("unknown nearest neighbor method");
232
+ }
190
233
 
191
234
  std::vector<Float> embedding(ndim * nobs);
192
235
 
193
- auto status = umap_ptr->initialize(knncolle_ptr.get(), ndim, embedding.data());
236
+ // Run UMAP calculation without GVL.
237
+ UmapRunData run_data = {
238
+ umap_ptr.get(),
239
+ knncolle_ptr.get(),
240
+ ndim,
241
+ &embedding};
242
+
243
+ rb_thread_call_without_gvl(
244
+ umap_run_without_gvl,
245
+ &run_data,
246
+ NULL,
247
+ NULL);
194
248
 
195
- int epoch_limit = 0;
196
- // tick is not implemented yet
197
- status.run(epoch_limit);
249
+ if (run_data.exception_thrown)
250
+ {
251
+ throw std::runtime_error(run_data.exception_message);
252
+ }
198
253
 
199
- // it is safe to cast to unsigned int
200
254
  auto na = numo::SFloat({(unsigned int)nobs, (unsigned int)ndim});
201
255
  std::copy(embedding.begin(), embedding.end(), na.write_ptr());
202
256
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Umappp
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.3"
5
5
  end
data/lib/umappp.rb CHANGED
@@ -19,7 +19,7 @@ module Umappp
19
19
  # Runs the Uniform Manifold Approximation and Projection (UMAP) dimensional
20
20
  # reduction technique.
21
21
  # @param embedding [Array, Numo::SFloat]
22
- # @param method [Symbol]
22
+ # @param method [Symbol, String]
23
23
  # @param ndim [Integer]
24
24
  # @param tick [Integer]
25
25
  # @param local_connectivity [Numeric]
@@ -30,7 +30,7 @@ module Umappp
30
30
  # @param a [Numeric]
31
31
  # @param b [Numeric]
32
32
  # @param repulsion_strength [Numeric]
33
- # @param initilaize [Umappp::InitMethod]
33
+ # @param initialize [Symbol, Umappp::InitMethod]
34
34
  # @param num_epochs [Integer]
35
35
  # @param learning_rate [Numeric]
36
36
  # @param negative_sample_rate [Numeric]
@@ -42,14 +42,43 @@ module Umappp
42
42
 
43
43
  def self.run(embedding, method: :annoy, ndim: 2, **params)
44
44
  unless (u = (params.keys - default_parameters.keys)).empty?
45
- raise ArgumentError, "[umappp.rb] unknown option : #{u.inspect}"
45
+ raise ArgumentError, "Unknown option(s): #{u.inspect}"
46
46
  end
47
47
 
48
48
  nnmethod = %i[annoy vptree].index(method.to_sym)
49
49
  raise ArgumentError, "method must be :annoy or :vptree" if nnmethod.nil?
50
50
 
51
+ # Allow initialize: to be specified as a Symbol or String and
52
+ # convert it to the corresponding Umappp::InitMethod enum.
53
+ if params.key?(:initialize)
54
+ init_val = params[:initialize]
55
+
56
+ if init_val.is_a?(Symbol) || init_val.is_a?(String)
57
+ init_sym = init_val.to_sym
58
+ mapping = {
59
+ spectral: InitMethod::SPECTRAL,
60
+ spectral_only: InitMethod::SPECTRAL_ONLY,
61
+ random: InitMethod::RANDOM,
62
+ none: InitMethod::NONE
63
+ }
64
+
65
+ mapped = mapping[init_sym]
66
+ unless mapped
67
+ raise ArgumentError,
68
+ "initialize must be one of :spectral, :spectral_only, :random, :none or a Umappp::InitMethod"
69
+ end
70
+
71
+ params[:initialize] = mapped
72
+ end
73
+ # If it's already a Umappp::InitMethod, we just pass it through.
74
+ end
75
+
51
76
  embedding2 = Numo::SFloat.cast(embedding)
52
- raise ArgumentError, "embedding must be a 2D array" if embedding2.ndim <= 1
77
+ if embedding2.ndim != 2
78
+ raise ArgumentError,
79
+ "embedding must be a 2D array, got #{embedding2.ndim}D with shape #{embedding2.shape.inspect}"
80
+ end
81
+ raise ArgumentError, "embedding must not be empty" if embedding2.empty?
53
82
 
54
83
  umappp_run(params, embedding2, ndim, nnmethod)
55
84
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: umappp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
@@ -456,7 +456,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
456
456
  - !ruby/object:Gem::Version
457
457
  version: '0'
458
458
  requirements: []
459
- rubygems_version: 3.6.7
459
+ rubygems_version: 3.7.2
460
460
  specification_version: 4
461
461
  summary: Umap for Ruby
462
462
  test_files: []