public QuantizedContourModel train(List<Contour> contours) {

    Pair<Double, Double> limits = identifyLimits(contours);
    ContourQuantizer cq = new ContourQuantizer(time_bins, value_bins, limits.first, limits.second);
    ConditionalDistribution[] slices = new ConditionalDistribution[time_bins];
    for (int i = 0; i < time_bins; ++i) {
      slices[i] = new ConditionalDistribution();
    }

    for (Contour c : contours) {
      try {
        // quantize the contour.
        int[] quantized = cq.quantize(c);
        assert quantized.length == slices.length;

        String prev_value = "";
        for (int i = 0; i < quantized.length; ++i) {
          String value = Integer.toString(quantized[i]);
          slices[i].add(prev_value, value);
          prev_value = value;
        }

      } catch (ContourQuantizerException e) {
        e.printStackTrace();
      }
    }

    // Normalize to use as a QCM.
    for (ConditionalDistribution cd : slices) {
      cd.normalize();
    }

    return new QuantizedContourModel(cq, slices);
  }