@Override
  public void init(String prefix) {
    // initialize global arm model
    GlobalArmModel.initialize(prefix);

    // initialize static fields
    K = (double) GlobalArmModel.numberOfArms();
    d = GlobalArmModel.getDValue();

    // initialize counters
    n = new double[GlobalArmModel.numberOfArms()];
    Arrays.fill(n, 0.0);
    sumN = 0.0;

    // model
    s = Arrays.copyOf(n, n.length);
    w = Arrays.copyOf(n, n.length);
    r = Arrays.copyOf(n, n.length);
    q = Arrays.copyOf(n, n.length);
    f = Arrays.copyOf(n, n.length);
    g = Arrays.copyOf(n, n.length);

    // parameter
    c = Configuration.getDouble(prefix + ".p2greedy.C");
  }
  public int update() {

    final double N = (double) Network.size();
    // final double m = Math.log(N)/Math.log(2.0);
    final double t = (double) ++age;

    // final double eps = c*K/(d*d*t*N*N);
    final double eps = Math.min(1.0, c * K / (d * d * t * N));
    int I = 0; // index of the arm which will be played in the current run

    if (t == 1) {
      I = CommonState.r.nextInt(GlobalArmModel.numberOfArms());
    } else {
      final double r = CommonState.r.nextDouble();
      if (r < eps) {
        // random
        I = CommonState.r.nextInt(GlobalArmModel.numberOfArms());
      } else {
        // best
        I = bestArmIdx();
      }
    }

    // play arm I
    final double xi = GlobalArmModel.playMachine(I);

    // update
    if (Utils.isPower2(t)) {
      addAndSetTo0(s, r);
      addAndSetTo0(w, q);
      addAndSetTo0(r, f);
      addAndSetTo0(q, g);
    }
    final double mul = N / 2.0;
    f[I] += mul * xi;
    g[I] += mul;

    // update counters
    n[I]++;
    sumN++;

    return I;
  }