#include "internal.h"
#include "logging.h"


void
kissat_enable_reluctant (reluctant * reluctant,
			 uint64_t period, uint64_t limit)
{
  if (limit && period > limit)
    period = limit;
  reluctant->limited = (limit > 0);
  reluctant->trigger = false;
  reluctant->period = period;
  reluctant->wait = period;
  reluctant->u = reluctant->v = 1;
  reluctant->limit = limit;
}

void
kissat_disable_reluctant (reluctant * reluctant)
{
  reluctant->period = 0;
}

void
kissat_tick_reluctant (reluctant * reluctant)
{
  if (!reluctant->period)
    return;

  if (reluctant->trigger)
    return;

  assert (reluctant->wait > 0);
  if (--reluctant->wait)
    return;

  uint64_t u = reluctant->u;
  uint64_t v = reluctant->v;

  if ((u & -u) == v)
    {
      u++;
      v = 1;
    }
  else
    {
      assert (UINT64_MAX / 2 >= v);
      v *= 2;
    }

  assert (v);
  assert (UINT64_MAX / v >= reluctant->period);
  uint64_t wait = v * reluctant->period;

  if (reluctant->limited && wait > reluctant->limit)
    {
      u = v = 1;
      wait = reluctant->period;
    }

  reluctant->trigger = true;
  reluctant->wait = wait;
  reluctant->u = u;
  reluctant->v = v;
}

void
kissat_init_reluctant (kissat * solver)
{
  if (GET_OPTION (reluctant))
    {
      LOG ("enable reluctant doubling with period %d limit %d",
	   GET_OPTION (reluctantint), GET_OPTION (reluctantlim));
      kissat_enable_reluctant (&solver->reluctant,
			       GET_OPTION (reluctantint),
			       GET_OPTION (reluctantlim));
    }
  else
    {
      LOG ("reluctant doubling disabled and thus no stable restarts");
      kissat_disable_reluctant (&solver->reluctant);
    }
}
