#ifndef CALLBACK_H
#define CALLBACK_H
#include "util.h"
const int kWindowSize = 20;
const int kMaxItersAllowed = 8e8;
const int kSwitchIters = 91000000;
class WesolowskiCallback :public INUDUPLListener {
public:
WesolowskiCallback(integer& D) {
vdfo = new vdf_original();
reducer = new PulmarkReducer();
this->D = D;
this->L = root(-D, 4);
}
virtual ~WesolowskiCallback() {
delete(vdfo);
delete(reducer);
}
void reduce(form& inf) {
reducer->reduce(inf);
}
void SetForm(int type, void *data, form* mulf, bool reduced = true) {
switch(type) {
case NL_SQUARESTATE:
{
uint64 res;
square_state_type *square_state=(square_state_type *)data;
if(!square_state->assign(mulf->a, mulf->b, mulf->c, res))
cout << "square_state->assign failed" << endl;
break;
}
case NL_FORM:
{
vdf_original::form *f=(vdf_original::form *)data;
mpz_set(mulf->a.impl, f->a);
mpz_set(mulf->b.impl, f->b);
mpz_set(mulf->c.impl, f->c);
break;
}
default:
cout << "Unknown case" << endl;
}
if (reduced) {
reduce(*mulf);
}
}
virtual void OnIteration(int type, void *data, uint64_t iteration) = 0;
std::unique_ptr<form[]> forms;
std::atomic<int64_t> iterations{0};
integer D;
integer L;
PulmarkReducer* reducer;
vdf_original* vdfo;
};
class OneWesolowskiCallback: public WesolowskiCallback {
public:
OneWesolowskiCallback(integer& D, form& f, uint64_t wanted_iter) : WesolowskiCallback(D) {
uint32_t k, l;
this->wanted_iter = wanted_iter;
if (wanted_iter >= (1 << 16)) {
ApproximateParameters(wanted_iter, l, k);
} else {
k = 10;
l = 1;
}
kl = k * l;
uint64_t space_needed = wanted_iter / (k * l) + 100;
forms.reset(new form[space_needed]);
forms[0] = f;
}
void OnIteration(int type, void *data, uint64_t iteration) {
iteration++;
if (iteration > wanted_iter)
return ;
if (iteration % kl == 0) {
uint64_t pos = iteration / kl;
form* mulf = &forms[pos];
SetForm(type, data, mulf);
}
if (iteration == wanted_iter) {
SetForm(type, data, &result);
}
}
uint64_t wanted_iter;
uint32_t kl;
form result;
};
class TwoWesolowskiCallback: public WesolowskiCallback {
public:
TwoWesolowskiCallback(integer& D, form f) : WesolowskiCallback(D) {
int space_needed = kSwitchIters / 10 + (kMaxItersAllowed - kSwitchIters) / 100;
forms.reset(new form[space_needed]);
forms[0] = f;
kl = 10;
switch_iters = -1;
}
void IncreaseConstants(uint64_t num_iters) {
kl = 100;
switch_iters = num_iters;
switch_index = num_iters / 10;
}
int GetPosition(uint64_t power) {
if (switch_iters == -1 || power < switch_iters) {
return power / 10;
} else {
return (switch_index + (power - switch_iters) / 100);
}
}
form *GetForm(uint64_t power) {
return &(forms[GetPosition(power)]);
}
bool LargeConstants() {
return kl == 100;
}
void OnIteration(int type, void *data, uint64_t iteration) {
iteration++;
if (iteration % kl == 0) {
uint64_t pos = GetPosition(iteration);
form* mulf = &forms[pos];
SetForm(type, data, mulf);
}
}
private:
uint64_t switch_index;
int64_t switch_iters;
uint32_t kl;
};
class FastAlgorithmCallback : public WesolowskiCallback {
public:
FastAlgorithmCallback(int segments, integer& D, form f, bool multi_proc_machine) : WesolowskiCallback(D) {
buckets_begin.push_back(0);
buckets_begin.push_back(bucket_size1 * window_size);
this->segments = segments;
this->multi_proc_machine = multi_proc_machine;
for (int i = 0; i < segments - 2; i++) {
buckets_begin.push_back(buckets_begin[buckets_begin.size() - 1] + bucket_size2 * window_size);
}
int space_needed = window_size * (bucket_size1 + bucket_size2 * (segments - 1));
forms.reset(new form[space_needed]);
checkpoints.reset(new form[1 << 18]);
y_ret = f;
for (int i = 0; i < segments; i++)
forms[buckets_begin[i]] = f;
checkpoints[0] = f;
}
int GetPosition(uint64_t exponent, int bucket) {
uint64_t power_2 = 1LL << (16 + 2 * bucket);
int position = buckets_begin[bucket];
int size = (bucket == 0) ? bucket_size1 : bucket_size2;
int kl = (bucket == 0) ? 10 : (12 * (power_2 >> 18));
position += ((exponent / power_2) % window_size) * size;
position += (exponent % power_2) / kl;
return position;
}
form *GetForm(uint64_t exponent, int bucket) {
uint64_t pos = GetPosition(exponent, bucket);
return &(forms[pos]);
}
void OnIteration(int type, void *data, uint64_t iteration) {
iteration++;
if (multi_proc_machine) {
if (iteration % (1 << 15) == 0) {
SetForm(type, data, &y_ret);
}
} else {
for (int i = 0; i < segments; i++) {
uint64_t power_2 = 1LL << (16 + 2LL * i);
int kl = (i == 0) ? 10 : (12 * (power_2 >> 18));
if ((iteration % power_2) % kl == 0) {
form* mulf = GetForm(iteration, i);
SetForm(type, data, mulf);
}
}
}
if (iteration % (1 << 16) == 0) {
form* mulf = (&checkpoints[(iteration / (1 << 16))]);
SetForm(type, data, mulf);
}
}
std::vector<int> buckets_begin;
std::unique_ptr<form[]> checkpoints;
form y_ret;
int segments;
const int bucket_size1 = 6554;
const int bucket_size2 = 21846;
const int window_size = kWindowSize;
bool multi_proc_machine;
};
#endif