private void calculate(double[] x) {

    value = 0.0;
    double[][] derivative = new double[labelIndex.size()][x.length/labelIndex.size()];
    double[][] weights = to2D(x);

    for (Datum datum : data) {
      double[] scores = new double[labelIndex.size()];
      for (Object feature : datum.features) {
        int f = featureIndex.indexOf(feature);
        if (f < 0) { continue; }
        for (int i = 0; i < labelIndex.size(); i++) {
          scores[i] += weights[i][f];
        }
      }

      double Z = logSum(scores);

      for (int i = 0; i < labelIndex.size(); i++) {
        double prob = Math.exp(scores[i] - Z);
        for (Object feature : datum.features) {
          int f = featureIndex.indexOf(feature);
          derivative[i][f] += prob;
          if (i == labelIndex.indexOf(datum.label)) {
            derivative[i][f]--;
          }
        }
        if (i == labelIndex.indexOf(datum.label)) {
          value -= Math.log(prob);
        }
      }
    }
    this.derivative = to1D(derivative);

    value += prior.compute(x, this.derivative);
  }