/** {@inheritDoc} */
  @Override
  public double getLogProbability(double value) {
    double prob = 0;

    int index = 0;
    for (Normal normal : this.terms) {
      prob = prob + this.coefficients[index] * normal.getProbability(value);
      index++;
    }
    return Math.log(prob);
  }
  /**
   * Creates a new GaussianMixture distribution for a given variable.
   *
   * @param var1 a {@link Variable} object.
   */
  public GaussianMixture(Variable var1) {
    this.var = var1;

    terms = new ArrayList<Normal>();
    Normal aux = new Normal(var1);
    aux.setMean(0);
    aux.setVariance(1);
    terms.add(aux);

    coefficients = new double[1];
    coefficients[0] = 1;
  }
  /** {@inheritDoc} */
  @Override
  public double[] getParameters() {

    int numParameters = 3 * coefficients.length;
    double[] parameters = new double[numParameters];

    int index = 0;
    for (Normal normal : this.terms) {
      parameters[3 * index] = this.coefficients[index];
      parameters[3 * index + 1] = normal.getMean();
      parameters[3 * index + 2] = normal.getVariance();
      index++;
    }
    return parameters;
  }
  /**
   * Sets the parameters of this GaussianMixture.
   *
   * @param params an Array of doubles containing the GaussianMixture parameters.
   */
  public void setParameters(double[] params) {
    if (params.length % 3 != 0) {
      throw new UnsupportedOperationException(
          "The number of parameters for the Gaussian mixture is not valid");
    } else {
      int numTerms = params.length / 3;

      this.coefficients = new double[numTerms];
      this.terms = new ArrayList<>(numTerms);

      for (int index = 0; index < numTerms; index++) {
        this.coefficients[index] = params[3 * index];
        Normal aux = new Normal(this.var);
        aux.setMean(params[3 * index + 1]);
        aux.setVariance(params[3 * index + 2]);
        this.terms.add(aux);
      }
    }
  };
  /**
   * Randomly initializes this GaussianMixture for a given number of terms.
   *
   * @param random a {@link java.util.Random} object.
   * @param numTerms a number of terms.
   */
  public void randomInitialization(Random random, int numTerms) {

    this.coefficients = new double[numTerms];
    this.terms = new ArrayList<>(numTerms);
    for (int k = 0; k < numTerms; k++) {
      this.coefficients[k] = random.nextDouble();

      Normal aux = new Normal(this.var);
      aux.setMean(5 * random.nextGaussian());
      aux.setVariance(random.nextDouble());

      this.terms.add(aux);
    }
    ;
    DoubleStream aux = Arrays.stream(this.coefficients);
    double suma = aux.sum();
    aux = Arrays.stream(this.coefficients);
    this.coefficients = aux.map(x -> x / suma).toArray();

    // System.out.println(coefficients);
    // this.coefficients = this.coefficients / .map().sum();

  }