diff --git a/CMakeLists.txt b/CMakeLists.txt index f12a34f..38261cc 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ project(TightInclusion LANGUAGES CXX VERSION "1.0.4") -option(TIGHT_INCLUSION_WITH_GMP "Enable rational based predicates (for debugging)" OFF) +option(TIGHT_INCLUSION_WITH_RATIONAL "Enable rational based predicates (for debugging)" OFF) option(TIGHT_INCLUSION_WITH_TIMER "Enable profiling timers (for debugging)" OFF) option(TIGHT_INCLUSION_WITH_DOUBLE_PRECISION "Enable double precision floating point numbers as input" ON) option(TIGHT_INCLUSION_LIMIT_QUEUE_SIZE "Enable limitation of maximal queue size" OFF) @@ -129,10 +129,10 @@ target_link_libraries(tight_inclusion PUBLIC Eigen3::Eigen) include(spdlog) target_link_libraries(tight_inclusion PUBLIC spdlog::spdlog) -# GMP (optional) -if(TIGHT_INCLUSION_WITH_GMP) - find_package(GMP REQUIRED) - target_link_libraries(tight_inclusion PUBLIC gmp::gmp) +# rational-cpp (optional) +if(TIGHT_INCLUSION_WITH_RATIONAL) + include(rational_cpp) + target_link_libraries(tight_inclusion PUBLIC rational::rational) endif() # Extra warnings (link last for highest priority) diff --git a/TightInclusionOptions.cmake.sample b/TightInclusionOptions.cmake.sample index 13f2a27..98b3797 100644 --- a/TightInclusionOptions.cmake.sample +++ b/TightInclusionOptions.cmake.sample @@ -28,7 +28,7 @@ # IPC Toolkit Options ################################################################################ -# option(TIGHT_INCLUSION_WITH_GMP "Enable rational based predicates (for debugging)" OFF) +# option(TIGHT_INCLUSION_WITH_RATIONAL "Enable rational based predicates (for debugging)" OFF) # option(TIGHT_INCLUSION_WITH_TIMER "Enable profiling timers (for debugging)" OFF) # option(TIGHT_INCLUSION_WITH_DOUBLE_PRECISION "Enable double precision floating point numbers as input" ON) # option(TIGHT_INCLUSION_LIMIT_QUEUE_SIZE "Enable limitation of maximal queue size" OFF) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 33b8984..7b0d608 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -12,14 +12,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.hpp.in" "${CMAKE_CURRENT_SOUR # Link to the required libraries if(TIGHT_INCLUSION_WITH_SAMPLE_QUERIES) - if(NOT TIGHT_INCLUSION_WITH_GMP) - find_package(GMP REQUIRED) - target_link_libraries(Tight_Inclusion_bin PUBLIC gmp::gmp) - endif() - target_sources(Tight_Inclusion_bin PUBLIC "read_rational_csv.cpp") - - include(sample_queries) - target_link_libraries(Tight_Inclusion_bin PUBLIC tight_inclusion::sample_queries) + include(ccd_query_io) + target_link_libraries(Tight_Inclusion_bin PUBLIC ccd_io::ccd_io) endif() include(pbar) diff --git a/app/main.cpp b/app/main.cpp index 2d3fdec..9059595 100755 --- a/app/main.cpp +++ b/app/main.cpp @@ -6,8 +6,7 @@ #include #ifdef TIGHT_INCLUSION_WITH_SAMPLE_QUERIES -#include -#include "read_rational_csv.hpp" +#include #endif #include @@ -21,7 +20,7 @@ using namespace ticcd; #ifdef TIGHT_INCLUSION_WITH_SAMPLE_QUERIES -static const std::string root_path(TIGHT_INCLUSION_SAMPLE_QUERIES_DIR); +static const std::string root_path(CCD_IO_SAMPLE_QUERIES_DIR); static const std::vector simulation_folders = {{ "chain", @@ -52,6 +51,8 @@ void check_sample_queries( const long max_itr, const bool print_progress = true) { + using Matrix8x3 = Eigen::Matrix; + const Eigen::Array3d err(-1, -1, -1); constexpr double t_max = 1; constexpr bool no_zero_toi = false; @@ -76,11 +77,12 @@ void check_sample_queries( for (const std::string &folder : folders) { fs::path dir = fs::path(root_path) / folder / sub_folder; for (const auto &csv : fs::directory_iterator(dir)) { - std::vector _; - const Eigen::MatrixXd all_V = - rational::read_rational_csv(csv.path().string(), _); - assert(all_V.rows() % 8 == 0); - total_number_of_queries += all_V.rows() / 8; + std::ifstream in_stream(csv.path().string()); + unsigned int line_count = std::count_if( + std::istreambuf_iterator{in_stream}, {}, + [](char c) { return c == '\n'; }); + assert(line_count % 8 == 0); + total_number_of_queries += line_count / 8; } } logger().trace("Total number of queries: {}", total_number_of_queries); @@ -94,21 +96,12 @@ void check_sample_queries( fs::path dir = fs::path(root_path) / folder / sub_folder; for (const auto &csv : fs::directory_iterator(dir)) { - std::vector results; - const Eigen::MatrixXd all_V = - rational::read_rational_csv(csv.path().string(), results); - - if (all_V.rows() % 8 != 0 || all_V.cols() != 3) { - logger().error( - "Incorrectly formatted data in file \"{}\": vertices should be of shape (8n)×3 where n is the number of queries! Got {}×{} instead.", - csv.path().string(), all_V.rows(), all_V.cols()); - assert(false); - continue; - } + const std::vector queries = + ccd_io::read_ccd_queries(csv.path().string()); - for (int i = 0; i < all_V.rows(); i += 8) { - const Eigen::Matrix V = all_V.middleRows<8>(i); - const bool expected_result = results[i]; + for (int i = 0; i < queries.size(); i++) { + Eigen::Map V(&queries[i].vertices[0][0]); + const bool expected_result = queries[i].ground_truth; total_positives += expected_result; // Output of CCD @@ -149,7 +142,7 @@ void check_sample_queries( logger().error( "False negative encountered in file \"{}\" (query #{})!", - csv.path().string(), i / 8); + csv.path().string(), i); for (int j = 0; j < 8; j++) { logger().debug( "V{}: {:.17f} {:.17f} {:.17f}", // diff --git a/app/read_rational_csv.cpp b/app/read_rational_csv.cpp deleted file mode 100644 index 88a6a27..0000000 --- a/app/read_rational_csv.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "read_rational_csv.hpp" - -#include -#include -#include - -#include -#include - -namespace ticcd::rational { - - // for debug - Eigen::MatrixXd - read_csv(const std::string &inputFileName, std::vector &results) - { - // be careful, there are n lines which means there are n/8 queries, but has - // n results, which means results are duplicated - results.clear(); - std::vector> vs; - vs.clear(); - std::ifstream infile; - infile.open(inputFileName); - std::array v; - if (!infile.is_open()) { - logger().error("Unable to open file {}!", inputFileName); - throw std::runtime_error("Unable to open file!"); - } - - int l = 0; - while (infile) // there is input overload classfile - { - l++; - std::string s; - if (!getline(infile, s)) - break; - if (l == 1) - continue; // skip the first row - if (s[0] != '#') { - std::istringstream ss(s); - std::array record; - int c = 0; - while (ss) { - std::string line; - if (!getline(ss, line, ',')) - break; - try { - - record[c] = line; - c++; - - } catch (const std::invalid_argument e) { - logger().error( - "NaN found in file {} line {}!", inputFileName, l); - throw std::runtime_error("NaN found in file!"); - } - } - - double x = std::stod(record[0]); - double y = std::stod(record[1]); - double z = std::stod(record[2]); - - v[0] = x; - v[1] = y; - v[2] = z; - vs.push_back(v); - - results.push_back(std::stod(record[4])); - } - } - - Eigen::MatrixXd all_v(vs.size(), 3); - for (int i = 0; i < vs.size(); i++) { - all_v(i, 0) = vs[i][0]; - all_v(i, 1) = vs[i][1]; - all_v(i, 2) = vs[i][2]; - } - if (!infile.eof()) { - logger().error("Could not read file {}!", inputFileName); - throw std::runtime_error("Could not read file!"); - } - - return all_v; - } - - Eigen::MatrixXd read_rational_csv( - const std::string &inputFileName, std::vector &results) - { - // be careful, there are n lines which means there are n/8 queries, but has - // n results, which means results are duplicated - results.clear(); - std::vector> vs; - vs.clear(); - std::ifstream infile; - infile.open(inputFileName); - std::array v; - if (!infile.is_open()) { - logger().error("Unable to open file {}!", inputFileName); - throw std::runtime_error("Unable to open file!"); - } - - int l = 0; - while (infile) // there is input overload classfile - { - l++; - std::string s; - if (!getline(infile, s)) - break; - if (s[0] != '#') { - std::istringstream ss(s); - std::array - record; // the first six are one vetex, - // the seventh is the result - int c = 0; - while (ss) { - std::string line; - if (!getline(ss, line, ',')) - break; - try { - record[c] = line; - c++; - } catch (const std::invalid_argument e) { - logger().error( - "NaN found in file {} line {}!", inputFileName, l); - throw std::runtime_error("NaN found in file!"); - } - } - Rational rt; - double x = rt.get_double(record[0], record[1]), - y = rt.get_double(record[2], record[3]), - z = rt.get_double(record[4], record[5]); - v[0] = x; - v[1] = y; - v[2] = z; - vs.push_back(v); - - results.push_back(bool(std::stoi(record[6]))); - } - } - Eigen::MatrixXd all_v(vs.size(), 3); - for (int i = 0; i < vs.size(); i++) { - all_v(i, 0) = vs[i][0]; - all_v(i, 1) = vs[i][1]; - all_v(i, 2) = vs[i][2]; - } - if (!infile.eof()) { - logger().error("Could not read file {}!", inputFileName); - throw std::runtime_error("Could not read file!"); - } - - return all_v; - } - -} // namespace ticcd::rational diff --git a/app/read_rational_csv.hpp b/app/read_rational_csv.hpp deleted file mode 100644 index b09a846..0000000 --- a/app/read_rational_csv.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#include - -namespace ticcd::rational { - - Eigen::MatrixXd read_rational_csv( - const std::string &inputFileName, std::vector &results); - Eigen::MatrixXd - read_csv(const std::string &inputFileName, std::vector &results); - -} // namespace ticcd::rational diff --git a/cmake/find/FindGMP.cmake b/cmake/find/FindGMP.cmake deleted file mode 100755 index 438e75f..0000000 --- a/cmake/find/FindGMP.cmake +++ /dev/null @@ -1,79 +0,0 @@ -# Try to find the GNU Multiple Precision Arithmetic Library (GMP) -# See http://gmplib.org/ - -find_path(GMP_INCLUDES - NAMES - gmp.h - PATHS - ENV GMP_DIR - ${GMP_WINDOWS_PATH} - ${INCLUDE_INSTALL_DIR} - PATH_SUFFIXES - include -) - -find_library(GMP_LIBRARIES - NAMES - gmp - libgmp - PATHS - ENV GMP_DIR - ${GMP_WINDOWS_PATH} - ${LIB_INSTALL_DIR} - PATH_SUFFIXES - lib -) - -set(GMP_EXTRA_VARS "") -if(WIN32) - # Find dll file and set IMPORTED_LOCATION to the .dll file - find_file(GMP_RUNTIME_LIB - NAMES - gmp.dll - libgmp-10.dll - PATHS - ENV GMP_DIR - ${GMP_WINDOWS_PATH} - ${LIB_INSTALL_DIR} - PATH_SUFFIXES - lib - ) - list(APPEND GMP_EXTRA_VARS GMP_RUNTIME_LIB) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GMP - REQUIRED_VARS - GMP_INCLUDES - GMP_LIBRARIES - ${GMP_EXTRA_VARS} - REASON_FAILURE_MESSAGE - "GMP is not installed on your system. Install GMP using your preferred package manager." -) -mark_as_advanced(GMP_INCLUDES GMP_LIBRARIES) - -if(GMP_INCLUDES AND GMP_LIBRARIES AND NOT TARGET gmp::gmp) - if(GMP_RUNTIME_LIB) - add_library(gmp::gmp SHARED IMPORTED) - else() - add_library(gmp::gmp UNKNOWN IMPORTED) - endif() - - # Set public header location and link language - set_target_properties(gmp::gmp PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDES}" - ) - - # Set lib location. On Windows we specify both the .lib and the .dll paths - if(GMP_RUNTIME_LIB) - set_target_properties(gmp::gmp PROPERTIES - IMPORTED_IMPLIB "${GMP_LIBRARIES}" - IMPORTED_LOCATION "${GMP_RUNTIME_LIB}" - ) - else() - set_target_properties(gmp::gmp PROPERTIES - IMPORTED_LOCATION "${GMP_LIBRARIES}" - ) - endif() -endif() diff --git a/cmake/recipes/ccd_query_io.cmake b/cmake/recipes/ccd_query_io.cmake new file mode 100644 index 0000000..d74a57d --- /dev/null +++ b/cmake/recipes/ccd_query_io.cmake @@ -0,0 +1,11 @@ +if(TARGET ccd_io::ccd_io) + return() +endif() + +message(STATUS "Third-party: creating target 'ccd_io::ccd_io'") + +set(CCD_IO_DOWNLOAD_SAMPLE_QUERIES ON CACHE BOOL "Download sample CCD queries" FORCE) +set(CCD_IO_SAMPLE_QUERIES_DIR "${PROJECT_SOURCE_DIR}/sample-queries/" CACHE PATH "Where should we download sample queries?") + +include(CPM) +CPMAddPackage("gh:Continuous-Collision-Detection/CCD-Query-IO#efca80cda21d95d74a1477ed22d42db8aabb5835") \ No newline at end of file diff --git a/cmake/recipes/cli11.cmake b/cmake/recipes/cli11.cmake index 24f3346..38d91e2 100644 --- a/cmake/recipes/cli11.cmake +++ b/cmake/recipes/cli11.cmake @@ -13,7 +13,7 @@ if(TARGET CLI11::CLI11) return() endif() -message(STATUS "Third-party (external): creating target 'CLI11::CLI11'") +message(STATUS "Third-party: creating target 'CLI11::CLI11'") include(CPM) CPMAddPackage("gh:CLIUtils/CLI11@2.3.2") \ No newline at end of file diff --git a/cmake/recipes/rational_cpp.cmake b/cmake/recipes/rational_cpp.cmake new file mode 100644 index 0000000..be6cea0 --- /dev/null +++ b/cmake/recipes/rational_cpp.cmake @@ -0,0 +1,8 @@ +if(TARGET rational::rational) + return() +endif() + +message(STATUS "Third-party: creating target 'rational::rational'") + +include(CPM) +CPMAddPackage("gh:zfergus/rational-cpp#1e91438315389db5987732f464c36614b31bcadf") \ No newline at end of file diff --git a/cmake/recipes/sample_queries.cmake b/cmake/recipes/sample_queries.cmake deleted file mode 100644 index 3005d36..0000000 --- a/cmake/recipes/sample_queries.cmake +++ /dev/null @@ -1,30 +0,0 @@ -if(TARGET tight_inclusion::sample_queries) - return() -endif() - -include(ExternalProject) -include(FetchContent) - -set(TIGHT_INCLUSION_SAMPLE_QUERIES_DIR "${PROJECT_SOURCE_DIR}/sample-queries/" CACHE PATH "Where should we download sample queries?") - -ExternalProject_Add( - sample_queries_download - PREFIX "${FETCHCONTENT_BASE_DIR}/sample-queries" - SOURCE_DIR ${TIGHT_INCLUSION_SAMPLE_QUERIES_DIR} - - GIT_REPOSITORY https://github.com/Continuous-Collision-Detection/Sample-Queries.git - GIT_TAG 4d6cce33477d8d5c666c31c8ea23e1aea97be371 - - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - LOG_DOWNLOAD ON -) - -# Create a dummy target for convenience -add_library(tight_inclusion_sample_queries INTERFACE) -add_library(tight_inclusion::sample_queries ALIAS tight_inclusion_sample_queries) - -add_dependencies(tight_inclusion_sample_queries sample_queries_download) - -target_compile_definitions(tight_inclusion_sample_queries INTERFACE TIGHT_INCLUSION_SAMPLE_QUERIES_DIR=\"${TIGHT_INCLUSION_SAMPLE_QUERIES_DIR}\") \ No newline at end of file diff --git a/src/tight_inclusion/CMakeLists.txt b/src/tight_inclusion/CMakeLists.txt index cef5218..479b915 100755 --- a/src/tight_inclusion/CMakeLists.txt +++ b/src/tight_inclusion/CMakeLists.txt @@ -20,6 +20,6 @@ target_sources(tight_inclusion PRIVATE ${SOURCES}) # Subfolders ################################################################################ -if(TIGHT_INCLUSION_WITH_GMP OR TIGHT_INCLUSION_WITH_TESTS) +if(TIGHT_INCLUSION_WITH_RATIONAL) add_subdirectory(rational) endif() diff --git a/src/tight_inclusion/config.hpp.in b/src/tight_inclusion/config.hpp.in index 67cc6b6..e10b433 100644 --- a/src/tight_inclusion/config.hpp.in +++ b/src/tight_inclusion/config.hpp.in @@ -8,7 +8,7 @@ #define TIGHT_INCLUSION_VER_MINOR "@PROJECT_VERSION_MINOR@" #define TIGHT_INCLUSION_VER_PATCH "@PROJECT_VERSION_PATCH@" -#cmakedefine TIGHT_INCLUSION_WITH_GMP +#cmakedefine TIGHT_INCLUSION_WITH_RATIONAL #cmakedefine TIGHT_INCLUSION_WITH_TIMER #cmakedefine TIGHT_INCLUSION_WITH_DOUBLE_PRECISION #cmakedefine TIGHT_INCLUSION_LIMIT_QUEUE_SIZE diff --git a/src/tight_inclusion/interval_root_finder.cpp b/src/tight_inclusion/interval_root_finder.cpp index ff5aa6e..c88c521 100644 --- a/src/tight_inclusion/interval_root_finder.cpp +++ b/src/tight_inclusion/interval_root_finder.cpp @@ -276,7 +276,7 @@ namespace ticcd { err_and_ms, box_in); } - // #ifdef TIGHT_INCLUSION_WITH_GMP // this is defined in the begining of this file + // #ifdef TIGHT_INCLUSION_WITH_RATIONAL // this is defined in the begining of this file // zero_in = origin_in_function_bounding_box_rational( // current, a_t0, b_t0, c_t0, d_t0, a_t1, b_t1, c_t1, d_t1); // #endif @@ -422,7 +422,7 @@ namespace ticcd { Array3 true_tol; { TIGHT_INCLUSION_SCOPED_TIMER(time_predicates); - // #ifdef TIGHT_INCLUSION_WITH_GMP // this is defined in the begining of this file + // #ifdef TIGHT_INCLUSION_WITH_RATIONAL // this is defined in the begining of this file // Array3 ms_3d = Array3::Constant(ms); // zero_in = origin_in_function_bounding_box_rational_return_tolerance( // current, a_t0, b_t0, c_t0, d_t0, a_t1, b_t1, c_t1, d_t1, diff --git a/src/tight_inclusion/rational/CMakeLists.txt b/src/tight_inclusion/rational/CMakeLists.txt index 4e795b0..c21bc3b 100644 --- a/src/tight_inclusion/rational/CMakeLists.txt +++ b/src/tight_inclusion/rational/CMakeLists.txt @@ -3,7 +3,6 @@ set(SOURCES ccd.hpp interval_root_finder.cpp interval_root_finder.hpp - rational.hpp ) source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${SOURCES}) diff --git a/src/tight_inclusion/rational/ccd.cpp b/src/tight_inclusion/rational/ccd.cpp index 9ac5357..91d1cc8 100644 --- a/src/tight_inclusion/rational/ccd.cpp +++ b/src/tight_inclusion/rational/ccd.cpp @@ -43,7 +43,7 @@ namespace ticcd::rational { // Return a conservative time-of-impact if (is_impacting) { - toi = toi_interval[0][0].to_double(); + toi = toi_interval[0][0]; } // This time of impact is very dangerous for convergence // assert(!is_impacting || toi > 0); @@ -84,7 +84,7 @@ namespace ticcd::rational { // Return a conservative time-of-impact if (is_impacting) { - toi = toi_interval[0][0].to_double(); + toi = toi_interval[0][0]; } // This time of impact is very dangerous for convergence diff --git a/src/tight_inclusion/rational/interval_root_finder.hpp b/src/tight_inclusion/rational/interval_root_finder.hpp index 6e17851..46d0ce1 100644 --- a/src/tight_inclusion/rational/interval_root_finder.hpp +++ b/src/tight_inclusion/rational/interval_root_finder.hpp @@ -6,11 +6,17 @@ #include #include #include -#include + +#include namespace ticcd::rational { + using namespace ::rational; typedef std::array RationalInterval; + typedef Eigen::Matrix + Vector3r; + typedef Eigen::Array + Array3r; bool edge_edge_interval_root_finder( const Vector3 &ea0_t0, diff --git a/src/tight_inclusion/rational/rational.hpp b/src/tight_inclusion/rational/rational.hpp deleted file mode 100644 index 061abe2..0000000 --- a/src/tight_inclusion/rational/rational.hpp +++ /dev/null @@ -1,281 +0,0 @@ -#pragma once - -#include -#include - -namespace ticcd { - class Rational { - public: - mpq_t value; - - void canonicalize() { mpq_canonicalize(value); } - - int get_sign() const { return mpq_sgn(value); } - - void print_numerator() - { - mpz_t numerator; - mpz_init(numerator); - mpq_get_num(numerator, value); - mpz_out_str(NULL, 10, numerator); - // long v=mpz_get_si(numerator); - mpz_clear(numerator); - } - - void print_denominator() - { - mpz_t denominator; - mpz_init(denominator); - mpq_get_den(denominator, value); - - mpz_out_str(NULL, 10, denominator); - // long v=mpz_get_si(denominator); - mpz_clear(denominator); - } - - long long get_numerator() - { - mpz_t numerator; - mpz_init(numerator); - - mpq_get_num(numerator, value); - long long v = mpz_get_si(numerator); - - mpz_clear(numerator); - return v; - } - - long long get_denominator() - { - mpz_t denominator; - mpz_init(denominator); - mpq_get_den(denominator, value); - - long long v = mpz_get_si(denominator); - // std::string s(mpz_get_str(NULL, 10, denominator)); - // long long v=std::stoll(s); - mpz_clear(denominator); - return v; - } - - std::string get_denominator_str() - { - mpz_t denominator; - mpz_init(denominator); - mpq_get_den(denominator, value); - - std::string v(mpz_get_str(NULL, 10, denominator)); - - mpz_clear(denominator); - return v; - } - - std::string get_numerator_str() - { - mpz_t numerator; - mpz_init(numerator); - - mpq_get_num(numerator, value); - std::string v(mpz_get_str(NULL, 10, numerator)); - ; - - mpz_clear(numerator); - return v; - } - - double get_double(const std::string &num, const std::string &denom) - { - std::string tmp = num + "/" + denom; - mpq_set_str(value, tmp.c_str(), 10); - return mpq_get_d(value); - } - - Rational() - { - mpq_init(value); - mpq_set_d(value, 0); - } - - Rational(double d) - { - assert(std::isfinite(d)); - mpq_init(value); - mpq_set_d(value, d); - canonicalize(); - } - - Rational(float d) - { - assert(std::isfinite(d)); - mpq_init(value); - double ddouble = d; // convert (float)d to double - mpq_set_d(value, ddouble); - canonicalize(); - } - - Rational(int i) - { - mpq_init(value); - mpq_set_si(value, i, 1U); - canonicalize(); - } - - Rational(long i) - { - mpq_init(value); - mpq_set_si(value, i, 1U); - canonicalize(); - } - - Rational(const mpq_t &v_) - { - mpq_init(value); - mpq_set(value, v_); - // canonicalize(); - } - - Rational(const Rational &other) - { - mpq_init(value); - mpq_set(value, other.value); - } - - ~Rational() { mpq_clear(value); } - - friend Rational operator-(const Rational &v) - { - Rational r_out; - mpq_neg(r_out.value, v.value); - return r_out; - } - - friend Rational operator+(const Rational &x, const Rational &y) - { - Rational r_out; - mpq_add(r_out.value, x.value, y.value); - return r_out; - } - - friend Rational operator-(const Rational &x, const Rational &y) - { - Rational r_out; - mpq_sub(r_out.value, x.value, y.value); - return r_out; - } - - friend Rational operator*(const Rational &x, const Rational &y) - { - Rational r_out; - mpq_mul(r_out.value, x.value, y.value); - return r_out; - } - - friend Rational operator/(const Rational &x, const Rational &y) - { - Rational r_out; - mpq_div(r_out.value, x.value, y.value); - return r_out; - } - - Rational &operator=(const Rational &x) - { - if (this == &x) - return *this; - mpq_set(value, x.value); - return *this; - } - - Rational &operator=(const double x) - { - mpq_set_d(value, x); - // canonicalize(); - return *this; - } - - Rational &operator=(const float x) - { - double xd = x; - mpq_set_d(value, xd); - // canonicalize(); - return *this; - } - - Rational &operator=(const int x) - { - mpq_set_si(value, x, 1U); - // canonicalize(); - return *this; - } - - Rational &operator=(const long x) - { - mpq_set_si(value, x, 1U); - // canonicalize(); - return *this; - } - - template bool operator<(const T &r1) - { - if constexpr (std::is_same::value) - return mpq_cmp(value, r1.value) < 0; - else - return *this < Rational(r1); - } - - template bool operator>(const T &r1) - { - if constexpr (std::is_same::value) - return mpq_cmp(value, r1.value) > 0; - else - return *this > Rational(r1); - } - - template bool operator<=(const T &r1) - { - if constexpr (std::is_same::value) - return mpq_cmp(value, r1.value) <= 0; - else - return *this <= Rational(r1); - } - - template bool operator>=(const T &r1) - { - if constexpr (std::is_same::value) - return mpq_cmp(value, r1.value) >= 0; - else - return *this >= Rational(r1); - } - - template bool operator==(const T &r1) - { - if constexpr (std::is_same::value) - return mpq_equal(value, r1.value); - else - return *this == Rational(r1); - } - - template bool operator!=(const T &r1) - { - if constexpr (std::is_same::value) - return !mpq_equal(value, r1.value); - else - return *this != Rational(r1); - } - - double to_double() const { return mpq_get_d(value); } - - operator double() const { return to_double(); } - - friend std::ostream &operator<<(std::ostream &os, const Rational &r) - { - os << mpq_get_d(r.value); - return os; - } - }; - - typedef Eigen::Matrix - Vector3r; - typedef Eigen::Array - Array3r; - -} // namespace ticcd