Nested static loop fails to work due to constexpr uncapturable - c++

I have this static_loop construct that is used for type dispatching over loop unrolling.
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { std::get<i * j>(ab) = i; });
// static_loop<2>([&, i = std::integral_constant<size_t, i>()](auto j) { std::get<i * j>(ab) = i; });
});
std::cout << a << " " << b << std::endl;
}
};
However it doesn't compile when doing nested loops. I'd assume i and j are both constexpr thus i * j is valid in std::get<>, however, compiler seems not allowing this. Is it possible to capture i as constexpr in the inner lambda?
Full example is at godbolt along with the error messages.

static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { std::get<i * j>(ab) }
}
The IDE correctly underlines the error for you. i * jis a multiplication of two variables, it is not a compile-time constant.
You can nest loops if you switch to template parameters rather than function arguments.

This somehow works. Not sure if it violates any standard rules.
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { auto ii = decltype(i)(); std::get<ii * j>(ab) = ii; });
});
std::cout << a << " " << b << std::endl;
}
};
The captured value might not be constexpr but its type is somehow retained.

Related

constexpr base case not considered during compilation

I was trying out the constexpr functions and stumbled upon the below example of implementing Fibonacci numbers
There is no logical difference between fibon2 and fibon1 but I still get the compilation error of exceeding template initializations for the fibon1.
What i'm missing here?
#include <cstdint>
#include <iostream>
template <int32_t x>
constexpr int32_t fibon2() {
if constexpr (x == 0)
return 1;
else if constexpr (x == 1)
return 1;
else if constexpr (x == 2)
return 1;
else
return fibon2<x - 1>() + fibon2<x - 2>();
}
template <int32_t x>
constexpr int32_t fibon1() {
if constexpr (x == 0) return 1;
if constexpr (x == 1) return 1;
if constexpr (x == 2) return 1;
return fibon1<x - 1>() + fibon1<x - 2>();
}
int32_t fibon3(int32_t x) {
if (x == 1) return 1;
if (x == 2) return 1;
return fibon3(x - 1) + fibon3(x - 2);
}
int main() {
std::cout << fibon3(2) << std::endl;
std::cout << fibon2<2>() << std::endl;
std::cout << fibon1<2>() << std::endl;
return 0;
}
The return in fibon1 is not under constexpr and thus has to be compiled regardless of the template argument provided.
Clang show this nicely: https://godbolt.org/z/577f15Kv1
If you put the return inside its own if constexpr then your fibon1 will compile:
template <int32_t x>
constexpr int32_t fibon1() {
if constexpr (x == 0) return 1;
if constexpr (x == 1) return 1;
if constexpr (x == 2) return 1;
if constexpr (x > 2)
return fibon1<x - 1>() + fibon1<x - 2>();
}
The last return in fibon2 is in a constexpr-if even though there's only an else there. It's the same as if you'd made it:
else if constexpr (x == 2)
return 1;
else if constexpr(true) // <- like this
return fibon2<x - 1>() + fibon2<x - 2>();
That's not the case in fibon1 which is why it fails. If you want a freestanding if constexpr for it, then
template <int32_t x>
constexpr int32_t fibon1() {
if constexpr (x == 0) return 1; // shouldn't this be 0 ?
if constexpr (x == 1) return 1;
if constexpr (x == 2) return 1; // this doesn't seem correct if fibon1<0> => 1
// added constexpr-if:
if constexpr (x < 0 || x > 2) return fibon1<x - 1>() + fibon1<x - 2>();
}
Note that the above will fail if you supply a negative value as a template parameter as it will never reach one of your terminating conditions. Either the recursion will be to deep or you'll get a signed integer overflow. If you instead want symmetry around 0, you can simply negate the template parameter and return value in case the template parameter is negative:
template <int32_t x>
constexpr int32_t fibon1() {
if constexpr (x < 0)
return -fibon1<-x>(); // like this
else if constexpr (x == 0 || x == 1) // assuming you want 0 for input 0
return x;
else
return fibon1<x - 1>() + fibon1<x - 2>();
}

Generate constexpr array (error: the value of 'sum' is not usable in a constant expression)

The Problem
I need to generate all possible partitions of an integer m into the sum of j elements a_k, where each a_k can be -1, 0, or 1. This is a deterministic algorithm and as such it should be able to implement it at compile time. I would like to return a std::array with all possible combinations as constexpr.
My Algorithm
Plain and simple, there are 3^j combinations in total. So we loop over all of them and check if the sum is m. The total number of valid combinations will be
\sum_{k=m}^{\lfloor (m+j)/2\rfloor}\binom{j}{k}\binom{j-k}{k-m}
Thus we can calculate the size of the array (which is j times the number above) and simply queue in all the number combinations we obtain by brute force.
My Code
Check it on Godbolt
I obtain the error
error: the value of 'sum' is not usable in a constant expression
88 | if constexpr( sum == m )
I fail to see however, how sum is not known at compile time.
How can I fix this?
#include <array>
#include <iostream>
#include <utility>
/** constexpr for loop **/
template <auto Start, auto End, auto Inc, class F>
constexpr void constexpr_for(F&& f)
{
if constexpr (Start < End)
{
f(std::integral_constant<decltype(Start), Start>());
constexpr_for<Start + Inc, End, Inc>(f);
}
}
/** constexpr binomials **/
template<std::size_t n, std::size_t k>
struct Binomial
{
constexpr static std::size_t value = (Binomial<n-1,k-1>::value + Binomial<n-1,k>::value);
};
template<>
struct Binomial<0,0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n>
struct Binomial<n,0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n>
struct Binomial<n,n>
{
constexpr static std::size_t value = 1;
};
template<std::size_t n, std::size_t k>
constexpr std::size_t binomial()
{
return Binomial<n,k>::value;
}
/** formula from the picture **/
template<std::size_t j, std::size_t m>
constexpr std::size_t n()
{
std::size_t result = 0;
constexpr_for<m, (j+m)/2+1, 1>([&result](auto k){
result += binomial<j, k>() * binomial<j-k, k-m>();
});
return result;
}
/** constexpr power function **/
template<std::size_t i, std::size_t j>
struct pow_t
{
constexpr static std::size_t value = i * pow_t<i, j-1>::value;
};
template<std::size_t i>
struct pow_t<i, 0>
{
constexpr static std::size_t value = 1;
};
template<std::size_t i, std::size_t j>
constexpr std::size_t pow()
{
return pow_t<i, j>::value;
}
/** actual function in question **/
template<std::size_t j, std::size_t m>
constexpr std::array<int, j*n<j,m>()> integer_compositions()
{
std::array<int, j*n<j,m>()> result;
std::size_t i = 0;
constexpr_for<0, pow<3, j>(), 1>([&](auto k)
{
std::array<std::size_t, j> partition;
std::size_t sum = 0;
constexpr_for<0, j, 1>([&](auto l)
{
partition[l] = -((k/static_cast<std::size_t>(pow<3,l>()))%3-1);
sum += partition[l];
});
if constexpr( sum == m ) // line 88
{
constexpr_for<0, j, 1>([&](auto l)
{
result[j*i + l] = partition[l];
});
++i;
}
});
return result;
}
int main()
{
constexpr auto list = integer_compositions<3, 1>();
return EXIT_SUCCESS;
}
You're confusing the purpose of constexpr function. A constexpr function can be executed both at runtime and as part of constant expression, that depends on how you use the function (and probably if the compiler wants to optimize things at compile time).
You don't need all these templated functions, since the whole purpose of constexpr functions is to avoid them for clarity, e.g., your binomial function can simply be:
constexpr std::size_t binomial(std::size_t n, std::size_t k) {
if (k == 0 || n == k) {
return 1;
}
else {
return binomial(n - 1, k - 1) + binomial(n - 1, k);
}
}
And you can then do:
// binomial(3, 2) is evaluated at compile-time
std::array<int, binomial(3, 2)> x;
static_assert(x.size() == 3);
This can be done for all of your functions, except the last one (integer_compositions) because the return type depends on the parameter, so you need a template here.
There are other issues in your code, for instance, you need to initialize your std::array in constexpr function, so std::array<..., ...> result{}(note the {} here).
Below is a working version of your code that does not use all of these templates (this requires C++20, but only because operator== for std::array is only constexpr since C++20):
#include <array>
#include <iostream>
/** constexpr binomials **/
constexpr std::size_t binomial(std::size_t n, std::size_t k) {
if (k == 0 || n == k) {
return 1;
}
else {
return binomial(n - 1, k - 1) + binomial(n - 1, k);
}
}
/** formula from the picture **/
constexpr std::size_t n(std::size_t j, std::size_t m)
{
std::size_t result = 0;
for (std::size_t k = m; k <= (j + m) / 2; ++k) {
result += binomial(j, k) * binomial(j - k, k - m);
}
return result;
}
/** constexpr power function **/
constexpr std::size_t pow(std::size_t a, std::size_t n) {
std::size_t r = 1;
while (n--) {
r *= a;
}
return r;
}
/** actual function in question **/
template<std::size_t j, std::size_t m>
constexpr std::array<int, j*n(j, m)> integer_compositions()
{
std::array<int, j*n(j, m)> result{};
std::size_t i = 0;
for (std::size_t k = 0; k < ::pow(3, j); ++k) {
std::array<std::size_t, j> partition{};
std::size_t sum = 0;
for (std::size_t l = 0; l < j; ++l) {
partition[l] = -((k/static_cast<std::size_t>(::pow(3, l)))%3-1);
sum += partition[l];
}
if (sum == m) // line 88
{
for (std::size_t l = 0; l < j; ++l) {
result[j*i + l] = partition[l];
}
++i;
}
}
return result;
}
int main()
{
static_assert(integer_compositions<3, 1>() == std::array<int, 18>{});
}
Note: The static assertion obviously fails because I have no clue what the 18 values are.

I have a question I have been trying on LeetCode and needed help in the error which is Time Limit exceeded

The link to the particular question is as follows: https://leetcode.com/problems/nth-magical-number/. My code is showing "Time Limit Exceeded" and I cannot figure out where actually lies the error in my code. My code is as follows:
class Solution {
public:
typedef unsigned int ull;
int gcd(int A,int B)
{
if(B==0)
return A;
else
return gcd(B,A%B);
}
int nthMagicalNumber(int N, int A, int B) {
ull m;
if(A<B)
{
int t;
t=A;
A=B;
B=t;
}
ull lcm=(A*B)/gcd(A,B);
ull l=2;
ull h=1e9;
ull n;
while(l<=h)
{
m=l+(h-1)/2;
n=(m/A)+(m/B)-(m/lcm);
if(n==N)
break;
else if(n<N)
l=m+1;
else if(n>N)
h=m-1;
}
ull x=(1e9)+7;
return (int)(m%x);
}
};
Can someone let me know where I am wrong and how can I correct the error?
You might want to use a debugger for that. This solution is just very similar (using Binary Search with gcd) and would pass through:
// This block might trivially optimize the exec time;
// Can be removed;
const static auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
return 0;
}();
#include <cstdint>
#include <vector>
const static struct Solution {
using SizeType = std::uint_fast64_t;
static constexpr SizeType kMod = 1e9 + 7;
const SizeType nthMagicalNumber(
const SizeType N,
const SizeType A,
const SizeType B
) {
const SizeType lowest_common_multiple = A * B / getGreatestCommonDivisor(A, B);
SizeType lo = 2;
SizeType hi = 1e14;
while (lo < hi) {
SizeType mid = lo + (hi - lo) / 2;
if (mid / A + mid / B - mid / lowest_common_multiple < N) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo % kMod;
}
// __gcd(a, b)
static const SizeType getGreatestCommonDivisor(
const SizeType a,
const SizeType b
) {
if (not b) {
return a;
}
return getGreatestCommonDivisor(b, a % b);
}
};
Instead of ull, here we are using std::uint_fast64_t.
References
For additional details, please see the Discussion Board which you can find plenty of well-explained accepted solutions in there, with a variety of languages including efficient algorithms and asymptotic time/space complexity analysis1, 2.
You can try this approach in C++ for that question my solution got accepted:
class Solution {
public:
long long gcd(long long a, long long b) {
if(b == 0)
return a;
return gcd(b, a % b);
}
int nthMagicalNumber(long long n, long long a, long long b) {
long long end = max(a, b) * (n + 1);
long long min = 1;
long long lcm = (a / gcd(a, b)) * b;
long long curr, mid;
while(min <= end) {
mid = (end - min)/2 + min;
curr = (mid / a) + (mid / b) - (mid / lcm);
if(curr > n) {
end = mid - 1;
} else if(curr < n) {
min = mid + 1;
} else {
break;
}
}
while((mid % a != 0) && (mid % b != 0)) {
mid--;
}
return mid % (1000000007);
}
};

Why if constexpr fails to bypass constexpr evaluation?

I'm building a static loop for type dispatching using macros. Here is
what I achieved so far.
#define LOOP(n, f) \
static_assert(n <= 8 && "static loop size should <= 8"); \
do { \
if constexpr (n >= 8) \
f(std::integral_constant<size_t, n - 8>()); \
if constexpr (n >= 7) \
f(std::integral_constant<size_t, n - 7>()); \
if constexpr (n >= 6) \
f(std::integral_constant<size_t, n - 6>()); \
if constexpr (n >= 5) \
f(std::integral_constant<size_t, n - 5>()); \
if constexpr (n >= 4) \
f(std::integral_constant<size_t, n - 4>()); \
if constexpr (n >= 3) \
f(std::integral_constant<size_t, n - 3>()); \
if constexpr (n >= 2) \
f(std::integral_constant<size_t, n - 2>()); \
if constexpr (n >= 1) \
f(std::integral_constant<size_t, n - 1>()); \
} while (0);
template <typename T> constexpr size_t tupleSize(T&) { return tuple_size_v<T>; }
int main() {
auto t = std::make_tuple(1, "string", 0.2, 3, 1, 1, 1);
LOOP(tupleSize(t), [&](auto i) { cout << std::get<i>(t) << endl; });
return 0;
}
And the godbolt link https://godbolt.org/z/GcMZI3
The question is, why do the first four branches fail the compilation?
Do not use a macro, use a function template instead. if constexpr works by discarding the non-taken branch depending on the current instantiation of a template.
template <std::size_t n, typename F>
void loop(F&& f)
{
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
Usage:
int main() {
constexpr auto t = std::make_tuple(1, "string", 0.2, 3);
loop<tupleSize(t)>([&](auto i) { cout << std::get<i>(t) << endl; });
return 0;
}
live example on godbolt.org
From cppreference:
If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated.
Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive

Pascal Triangle Recursive Program optimization in C++

I have built recursive function to compute Pascal's triangle values.
Is there a way to optimize it?
Short reminder about Pascal's triangle: C(n, k) = C(n-1, k-1) + C(n-1, k)
My code is:
int Pascal(int n, int k) {
if (k == 0) return 1;
if (n == 0) return 0;
return Pascal(n - 1, k - 1) + Pascal(n - 1, k);
}
The inefficiency I see is that it stores some values twice.
Example:
C(6,2) = C(5,1) + C(5,2)
C(6,2) = C(4,0) + C(4,1) + C(4,1) + C(4,2)
it will call C(4,1) twice
Any idea how to optimize this function?
Thanks
The following routine will compute the n-choose-k, using the recursive definition and memoization. The routine is extremely fast and accurate:
inline unsigned long long n_choose_k(const unsigned long long& n,
const unsigned long long& k)
{
if (n < k) return 0;
if (0 == n) return 0;
if (0 == k) return 1;
if (n == k) return 1;
if (1 == k) return n;
typedef unsigned long long value_type;
class n_choose_k_impl
{
public:
n_choose_k_impl(value_type* table,const value_type& dimension)
: table_(table),
dimension_(dimension / 2)
{}
inline value_type& lookup(const value_type& n, const value_type& k)
{
const std::size_t difference = static_cast<std::size_t>(n - k);
return table_[static_cast<std::size_t>((dimension_ * n) + ((k < difference) ? k : difference))];
}
inline value_type compute(const value_type& n, const value_type& k)
{
// n-Choose-k = (n-1)-Choose-(k-1) + (n-1)-Choose-k
if ((0 == k) || (k == n))
return 1;
value_type v1 = lookup(n - 1,k - 1);
if (0 == v1)
v1 = lookup(n - 1,k - 1) = compute(n - 1,k - 1);
value_type v2 = lookup(n - 1,k);
if (0 == v2)
v2 = lookup(n - 1,k) = compute(n - 1,k);
return v1 + v2;
}
value_type* table_;
const value_type dimension_;
};
static const std::size_t static_table_dim = 100;
static const std::size_t static_table_size = static_cast<std::size_t>((static_table_dim * static_table_dim) / 2);
static value_type static_table[static_table_size];
static bool static_table_initialized = false;
if (!static_table_initialized && (n <= static_table_dim))
{
std::fill_n(static_table,static_table_size,0);
static_table_initialized = true;
}
const std::size_t table_size = static_cast<std::size_t>(n * (n / 2) + (n & 1));
unsigned long long dimension = static_table_dim;
value_type* table = 0;
if (table_size <= static_table_size)
table = static_table;
else
{
dimension = n;
table = new value_type[table_size];
std::fill_n(table,table_size,0LL);
}
value_type result = n_choose_k_impl(table,dimension).compute(n,k);
if (table != static_table)
delete [] table;
return result;
}
Keep a table of previously returned results (indexed by their n and k values); the technique used there is memoization. You can also change the recursion to an iteration and use dynamic programming to fill in an array containing the triangle for n and k values smaller than the one you are trying to evaluate, then just get one element from it.