diff --git a/ext/alglib/alglib.cpp b/ext/alglib/alglib.cpp index b764ab1..991cfde 100644 --- a/ext/alglib/alglib.cpp +++ b/ext/alglib/alglib.cpp @@ -4,8 +4,8 @@ // #include "numo.hpp" #include "dataanalysis.h" #include "statistics.h" -#include "alglib_array_converters.hpp" -#include "alglib_utils.hpp" +#include "alglib_array_converters.h" +#include "alglib_utils.h" using namespace Rice; diff --git a/ext/alglib/alglib_array_converters.cpp b/ext/alglib/alglib_array_converters.cpp new file mode 100644 index 0000000..0f186f1 --- /dev/null +++ b/ext/alglib/alglib_array_converters.cpp @@ -0,0 +1,81 @@ + +#include "alglib_array_converters.h" + +// Convert Ruby Array to real_1d_array +alglib::real_1d_array ruby_array_to_real_1d_array(Array ruby_array) +{ + alglib::real_1d_array real_array; + real_array.setlength(ruby_array.size()); + std::transform(ruby_array.begin(), ruby_array.end(), real_array.getcontent(), [](const Object &o) + { return detail::From_Ruby().convert(o.value()); }); + return real_array; +} + +// Convert Ruby Array to integer_1d_array +alglib::integer_1d_array ruby_array_to_integer_1d_array(Array ruby_array) +{ + alglib::integer_1d_array integer_array; + integer_array.setlength(ruby_array.size()); + std::transform(ruby_array.begin(), ruby_array.end(), integer_array.getcontent(), [](const Object &o) + { return detail::From_Ruby().convert(o.value()); }); + return integer_array; +} + +/* +Below functions are experimental implementations. +Do not expect this to work! +*/ + +// Convert Ruby 2d Array to real_2d_array +alglib::real_2d_array ruby_array_to_real_2d_array(Array ruby_array, int &rows, int &cols) +{ + alglib::real_2d_array real_array; + rows = ruby_array.size(); + cols = detail::From_Ruby().convert(ruby_array.call("first")).size(); + // debug + real_array.setlength(rows, cols); + + Array::iterator it = ruby_array.begin(); + Array::iterator end = ruby_array.end(); + + for (int i = 0; it != end; ++it, ++i) + { + Array row = detail::From_Ruby().convert(it->value()); + // check if all rows have the same size + if (row.size() != cols) + { + throw std::invalid_argument("All rows must have the same size"); + } + + std::transform(row.begin(), row.end(), real_array[i], [](const Object &o) + { return detail::From_Ruby().convert(o.value()); }); + } + return real_array; +} + +// Convert real_1d_array to Ruby Array +Array real_1d_array_to_ruby_array(alglib::real_1d_array real_array) +{ + Array result; + for (int i = 0; i < real_array.length(); i++) + { + result.push(real_array[i]); + } + return result; +} + +// Convert real_2d_array to Ruby Array +Array real_2d_array_to_ruby_array(alglib::real_2d_array real_array) +{ + Array result; + for (int i = 0; i < real_array.rows(); i++) + { + Array row; + for (int j = 0; j < real_array.cols(); j++) + { + row.push(real_array[i][j]); + } + result.push(row); + } + return result; +} \ No newline at end of file diff --git a/ext/alglib/alglib_array_converters.hpp b/ext/alglib/alglib_array_converters.hpp deleted file mode 100644 index a9b4371..0000000 --- a/ext/alglib/alglib_array_converters.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include "ap.h" - -using namespace Rice; - -alglib::real_1d_array ruby_array_to_real_1d_array(Array ruby_array); - -// Experimental implementations - do not expect this to work! - -alglib::integer_1d_array ruby_array_to_integer_1d_array(Array ruby_array); -alglib::real_2d_array ruby_array_to_real_2d_array(Array ruby_array, int &rows, int &cols); -Array real_1d_array_to_ruby_array(alglib::real_1d_array real_array); -Array real_2d_array_to_ruby_array(alglib::real_2d_array real_array); diff --git a/ext/alglib/alglib_utils.cpp b/ext/alglib/alglib_utils.cpp index 0ed825c..32e313d 100644 --- a/ext/alglib/alglib_utils.cpp +++ b/ext/alglib/alglib_utils.cpp @@ -1,4 +1,4 @@ -#include "alglib_utils.hpp" +#include "alglib_utils.h" // Check if two arrays are the same size void check_size(Array x, Array y) diff --git a/ext/alglib/alglib_utils.hpp b/ext/alglib/alglib_utils.hpp deleted file mode 100644 index b974c0e..0000000 --- a/ext/alglib/alglib_utils.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include - -using namespace Rice; - -void check_size(Array x, Array y); \ No newline at end of file diff --git a/test/dataanalysis_test.rb b/test/dataanalysis_test.rb index 579c554..123cef1 100644 --- a/test/dataanalysis_test.rb +++ b/test/dataanalysis_test.rb @@ -18,6 +18,15 @@ def test_sample_mean v_r <- pca$rotation sort(abs(as.vector(v_r)), decreasing = TRUE)[1:6] R + + # Why [1:6]? + # Because otherwise, the results would span multiple lines. + # [1] 0.8164966 0.7071068 0.7071068 0.5773503 0.5773503 0.5773503 0.4082483 + # [8] 0.4082483 0.0000000 + + # Why take the absolute value and sort? + # Because the direction of eigenvectors is arbitrary. + expected_v_sort5 = v_sort5.split.map(&:to_f) result = Alglib.pca_build_basis( @@ -31,8 +40,6 @@ def test_sample_mean assert_in_delta expected_s2[1], result['s2'][1], DELTA assert_in_delta expected_s2[2], result['s2'][2], DELTA - p expected_v_sort5 - p actual_v_sort5 = result['v'].flatten.map(&:abs).sort.reverse[0..5] assert_in_delta expected_v_sort5[0], actual_v_sort5[0], DELTA assert_in_delta expected_v_sort5[1], actual_v_sort5[1], DELTA assert_in_delta expected_v_sort5[2], actual_v_sort5[2], DELTA