diff --git a/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.hpp b/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.hpp index e3f42ba..26304c2 100755 --- a/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.hpp +++ b/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.hpp @@ -28,6 +28,8 @@ namespace libfqfft { FieldT arithmetic_generator; void do_precomputation(); + static bool valid_for_size(const size_t m); + arithmetic_sequence_domain(const size_t m); void FFT(std::vector &a); diff --git a/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.tcc b/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.tcc index 3b59ae2..8ae9431 100755 --- a/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.tcc +++ b/libfqfft/evaluation_domain/domains/arithmetic_sequence_domain.tcc @@ -23,6 +23,18 @@ namespace libfqfft { +template +bool arithmetic_sequence_domain::valid_for_size(const size_t m) +{ + if (m <=1) + return false; + + if (FieldT::arithmetic_generator() == FieldT::zero()) + return false; + + return true; +} + template arithmetic_sequence_domain::arithmetic_sequence_domain(const size_t m) : evaluation_domain(m) { diff --git a/libfqfft/evaluation_domain/domains/basic_radix2_domain.hpp b/libfqfft/evaluation_domain/domains/basic_radix2_domain.hpp index 7b77b29..2ce3dc1 100755 --- a/libfqfft/evaluation_domain/domains/basic_radix2_domain.hpp +++ b/libfqfft/evaluation_domain/domains/basic_radix2_domain.hpp @@ -26,6 +26,8 @@ class basic_radix2_domain : public evaluation_domain { FieldT omega; + static bool valid_for_size(const size_t m); + basic_radix2_domain(const size_t m); void FFT(std::vector &a); diff --git a/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc b/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc index 2486f7a..7365ca6 100755 --- a/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc +++ b/libfqfft/evaluation_domain/domains/basic_radix2_domain.tcc @@ -22,6 +22,27 @@ namespace libfqfft { +template +bool basic_radix2_domain::valid_for_size(const size_t m) +{ + if ( m <= 1 ) + return false; + + // Will `get_root_of_unity` throw? + if (!std::is_same::value) + { + const size_t logm = libff::log2(m); + + if (logm > FieldT::s) + return false; + } + + if( get_root_of_unity_will_throw(m) ) + return false; + + return true; +} + template basic_radix2_domain::basic_radix2_domain(const size_t m) : evaluation_domain(m) { diff --git a/libfqfft/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/libfqfft/evaluation_domain/domains/basic_radix2_domain_aux.tcc index 3c00e5a..6ecbe60 100755 --- a/libfqfft/evaluation_domain/domains/basic_radix2_domain_aux.tcc +++ b/libfqfft/evaluation_domain/domains/basic_radix2_domain_aux.tcc @@ -61,7 +61,7 @@ void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) // w_m is 2^s-th root of unity now const FieldT w_m = omega^(n/(2*m)); - asm volatile ("/* pre-inner */"); + //asm volatile ("/* pre-inner */"); for (size_t k = 0; k < n; k += 2*m) { FieldT w = FieldT::one(); @@ -73,7 +73,7 @@ void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) w *= w_m; } } - asm volatile ("/* post-inner */"); + //asm volatile ("/* post-inner */"); m *= 2; } } diff --git a/libfqfft/evaluation_domain/domains/extended_radix2_domain.hpp b/libfqfft/evaluation_domain/domains/extended_radix2_domain.hpp index 7637925..53e9c11 100755 --- a/libfqfft/evaluation_domain/domains/extended_radix2_domain.hpp +++ b/libfqfft/evaluation_domain/domains/extended_radix2_domain.hpp @@ -27,6 +27,8 @@ class extended_radix2_domain : public evaluation_domain { FieldT omega; FieldT shift; + static bool valid_for_size(const size_t m); + extended_radix2_domain(const size_t m); void FFT(std::vector &a); diff --git a/libfqfft/evaluation_domain/domains/extended_radix2_domain.tcc b/libfqfft/evaluation_domain/domains/extended_radix2_domain.tcc index b6a31fa..50dfea0 100755 --- a/libfqfft/evaluation_domain/domains/extended_radix2_domain.tcc +++ b/libfqfft/evaluation_domain/domains/extended_radix2_domain.tcc @@ -17,6 +17,29 @@ namespace libfqfft { +template +bool extended_radix2_domain::valid_for_size(const size_t m) +{ + if ( m <= 1 ) + return false; + + // Will `get_root_of_unity` throw? + if (!std::is_same::value) + { + const size_t logm = libff::log2(m); + + if (logm != (FieldT::s + 1)) + return false; + } + + size_t small_m = m / 2; + + if( get_root_of_unity_will_throw(small_m) ) + return false; + + return true; +} + template extended_radix2_domain::extended_radix2_domain(const size_t m) : evaluation_domain(m) { diff --git a/libfqfft/evaluation_domain/domains/geometric_sequence_domain.hpp b/libfqfft/evaluation_domain/domains/geometric_sequence_domain.hpp index 22bd783..70a2da2 100755 --- a/libfqfft/evaluation_domain/domains/geometric_sequence_domain.hpp +++ b/libfqfft/evaluation_domain/domains/geometric_sequence_domain.hpp @@ -27,6 +27,8 @@ namespace libfqfft { std::vector geometric_triangular_sequence; void do_precomputation(); + static bool valid_for_size(const size_t m); + geometric_sequence_domain(const size_t m); void FFT(std::vector &a); diff --git a/libfqfft/evaluation_domain/domains/geometric_sequence_domain.tcc b/libfqfft/evaluation_domain/domains/geometric_sequence_domain.tcc index 1535810..fe5bdaa 100755 --- a/libfqfft/evaluation_domain/domains/geometric_sequence_domain.tcc +++ b/libfqfft/evaluation_domain/domains/geometric_sequence_domain.tcc @@ -23,6 +23,18 @@ namespace libfqfft { +template +bool geometric_sequence_domain::valid_for_size(const size_t m) +{ + if ( m <= 1 ) + return false; + + if (FieldT::geometric_generator() == FieldT::zero()) + return false; + + return true; +} + template geometric_sequence_domain::geometric_sequence_domain(const size_t m) : evaluation_domain(m) { diff --git a/libfqfft/evaluation_domain/domains/step_radix2_domain.hpp b/libfqfft/evaluation_domain/domains/step_radix2_domain.hpp index 33ba7f4..72fc090 100755 --- a/libfqfft/evaluation_domain/domains/step_radix2_domain.hpp +++ b/libfqfft/evaluation_domain/domains/step_radix2_domain.hpp @@ -29,6 +29,8 @@ class step_radix2_domain : public evaluation_domain { FieldT big_omega; FieldT small_omega; + static bool valid_for_size(const size_t m); + step_radix2_domain(const size_t m); void FFT(std::vector &a); diff --git a/libfqfft/evaluation_domain/domains/step_radix2_domain.tcc b/libfqfft/evaluation_domain/domains/step_radix2_domain.tcc index e9a984e..733975e 100755 --- a/libfqfft/evaluation_domain/domains/step_radix2_domain.tcc +++ b/libfqfft/evaluation_domain/domains/step_radix2_domain.tcc @@ -17,6 +17,29 @@ namespace libfqfft { +template +bool step_radix2_domain::valid_for_size(const size_t m) +{ + if ( m <= 1 ) + return false; + + const size_t big_m = 1ul<<(libff::log2(m)-1); + const size_t small_m = m - big_m; + + if (small_m != 1ul<(1ul<(1ul< step_radix2_domain::step_radix2_domain(const size_t m) : evaluation_domain(m) { diff --git a/libfqfft/evaluation_domain/evaluation_domain.hpp b/libfqfft/evaluation_domain/evaluation_domain.hpp index 57c4f67..48d9621 100755 --- a/libfqfft/evaluation_domain/evaluation_domain.hpp +++ b/libfqfft/evaluation_domain/evaluation_domain.hpp @@ -27,9 +27,34 @@ #define EVALUATION_DOMAIN_HPP_ #include +#include namespace libfqfft { +template +typename std::enable_if::value, bool>::type +get_root_of_unity_will_throw(const size_t n) +{ + return false; +} + + +template +typename std::enable_if::value, bool>::type +get_root_of_unity_will_throw(const size_t n) +{ + const size_t logn = libff::log2(n); + + if (n != (1u << logn)) + return true; + + if (logn > FieldT::s) + return true; + + return false; +} + + /** * An evaluation domain. */ diff --git a/libfqfft/evaluation_domain/get_evaluation_domain.tcc b/libfqfft/evaluation_domain/get_evaluation_domain.tcc index 299537c..282b2f3 100755 --- a/libfqfft/evaluation_domain/get_evaluation_domain.tcc +++ b/libfqfft/evaluation_domain/get_evaluation_domain.tcc @@ -38,15 +38,33 @@ std::shared_ptr > get_evaluation_domain(const size_t m const size_t small = min_size - big; const size_t rounded_small = (1ul<(min_size)); } - catch(...) { try { result.reset(new extended_radix2_domain(min_size)); } - catch(...) { try { result.reset(new step_radix2_domain(min_size)); } - catch(...) { try { result.reset(new basic_radix2_domain(big + rounded_small)); } - catch(...) { try { result.reset(new extended_radix2_domain(big + rounded_small)); } - catch(...) { try { result.reset(new step_radix2_domain(big + rounded_small)); } - catch(...) { try { result.reset(new geometric_sequence_domain(min_size)); } - catch(...) { try { result.reset(new arithmetic_sequence_domain(min_size)); } - catch(...) { throw DomainSizeException("get_evaluation_domain: no matching domain"); }}}}}}}} + if ( basic_radix2_domain::valid_for_size(min_size) ) { + result.reset(new basic_radix2_domain(min_size)); + } + else if ( extended_radix2_domain::valid_for_size(min_size) ) { + result.reset(new extended_radix2_domain(min_size)); + } + else if ( step_radix2_domain::valid_for_size(min_size) ) { + result.reset(new step_radix2_domain(min_size)); + } + else if ( basic_radix2_domain::valid_for_size(big + rounded_small) ) { + result.reset(new basic_radix2_domain(big + rounded_small)); + } + else if ( extended_radix2_domain::valid_for_size(big + rounded_small) ) { + result.reset(new extended_radix2_domain(big + rounded_small)); + } + else if ( step_radix2_domain::valid_for_size(big + rounded_small) ) { + result.reset(new step_radix2_domain(big + rounded_small)); + } + else if ( geometric_sequence_domain::valid_for_size(min_size) ) { + result.reset(new geometric_sequence_domain(min_size)); + } + else if ( arithmetic_sequence_domain::valid_for_size(min_size) ) { + result.reset(new arithmetic_sequence_domain(min_size)); + } + else { + throw DomainSizeException("get_evaluation_domain: no matching domain"); + } return result; }