/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.randomutils;

import com.helger.numbercruncher.mathutils.SystemOutAlignRight;

/**
 * Counters of random values that fall within each interval.
 */
public class Buckets
{
  private static final int MAX_BAR_SIZE = 50;

  private final SystemOutAlignRight m_aAlignRight = new SystemOutAlignRight (System.out);

  /** number of intervals */
  private final int m_n;
  /** counters per interval */
  private final int m_aCounters[];

  /** minimum random value */
  private float m_fMin;
  /** maximum random value */
  private float m_fMax;
  /** from min to max */
  private float m_fWidth;

  /**
   * Constructor.
   *
   * @param n
   *        the number of intervals
   */
  public Buckets (final int n)
  {
    m_n = n;
    m_aCounters = new int [n];
    clear ();
  }

  /**
   * Return the counter value for interval i.
   *
   * @param i
   *        the value of i
   * @return the counter value
   */
  public int get (final int i)
  {
    return m_aCounters[i];
  }

  /**
   * Set the minimum and maximum random values.
   *
   * @param rMin
   *        the minimum value
   * @param rMax
   *        the maximum value
   */
  public void setLimits (final float rMin, final float rMax)
  {
    this.m_fMin = rMin;
    this.m_fMax = rMax;
    this.m_fWidth = (rMax - rMin) / m_n;
  }

  /**
   * Determine a random value's interval and count it.
   *
   * @param r
   *        the random value
   */
  public void put (final float r)
  {
    // Ignore the value if it's out of range.
    if ((r < m_fMin) || (r > m_fMax))
      return;

    // Determine its interval and count it.
    final int i = (int) ((r - m_fMin) / m_fWidth);
    ++m_aCounters[i];
  }

  /**
   * Clear all the interval counters.
   */
  public void clear ()
  {
    for (int i = 0; i < m_aCounters.length; ++i)
      m_aCounters[i] = 0;
  }

  /**
   * Print the counter values as a horizontal bar chart. Scale the chart so that
   * the longest bar is MAX_BAR_SIZE.
   */
  public void print ()
  {
    // Get the longest bar's length.
    int maxCount = 0;
    for (int i = 0; i < m_n; ++i)
    {
      maxCount = Math.max (maxCount, m_aCounters[i]);
    }

    // Compute the scaling factor.
    final float factor = ((float) MAX_BAR_SIZE) / maxCount;

    // Loop to print each bar.
    for (int i = 0; i < m_n; ++i)
    {
      final int b = m_aCounters[i];

      // Interval number.
      m_aAlignRight.print (i, 2);
      m_aAlignRight.print (b, 7);
      System.out.print (": ");

      // Bar.
      final int length = Math.round (factor * b);
      for (int j = 0; j < length; ++j)
        System.out.print ("*");
      System.out.println ();
    }
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Perform basic complex arithmetic. The complex objects are immutable, and
 * complex operations create new complex objects.
 */
public class Complex
{
  /** the real part */
  private final float m_fReal;
  /** the imaginary part */
  private final float m_fImaginary;

  /**
   * Constructor.
   *
   * @param real
   *        the real part
   * @param imaginary
   *        the imaginary part
   */
  public Complex (final float real, final float imaginary)
  {
    m_fReal = real;
    m_fImaginary = imaginary;
  }

  /**
   * Return this complex number's real part.
   *
   * @return the real part
   */
  public float real ()
  {
    return m_fReal;
  }

  /**
   * Return this complex number's imaginary part.
   *
   * @return the imaginary part
   */
  public float imaginary ()
  {
    return m_fImaginary;
  }

  /**
   * @return Compute this complex number's modulus
   */
  public float modulus ()
  {
    return (float) Math.sqrt (m_fReal * m_fReal + m_fImaginary * m_fImaginary);
  }

  /**
   * Return whether or not this complex number is equal to another one.
   *
   * @param z
   *        the other complex number
   * @return true if equal, false if not
   */
  public boolean equal (final Complex z)
  {
    return (m_fReal == z.real ()) && (m_fImaginary == z.imaginary ());
  }

  /**
   * Add another complex number to this one.
   *
   * @param z
   *        the other complex number
   * @return a new complex number that is the sum
   */
  public Complex add (final Complex z)
  {
    return new Complex (m_fReal + z.real (), m_fImaginary + z.imaginary ());
  }

  /**
   * Subtract another complex number from this one.
   *
   * @param z
   *        the other complex number
   * @return a new complex number that is the difference
   */
  public Complex subtract (final Complex z)
  {
    return new Complex (m_fReal - z.real (), m_fImaginary - z.imaginary ());
  }

  /**
   * Multiply this complex number by another one.
   *
   * @param z
   *        the other complex number
   * @return a new complex number that is the product
   */
  public Complex multiply (final Complex z)
  {
    return new Complex (m_fReal * z.real () -
                        m_fImaginary * z.imaginary (),
                        m_fReal * z.imaginary () + m_fImaginary * z.real ());
  }

  /**
   * Divide this complex number by another one.
   *
   * @param z
   *        the other complex number
   * @return a new complex number that is the quotient
   */
  public Complex divide (final Complex z)
  {
    final float denom = z.real () * z.real () + z.imaginary () * z.imaginary ();
    final float qr = (m_fReal * z.real () + m_fImaginary * z.imaginary ()) / denom;
    final float qi = (m_fImaginary * z.real () - m_fReal * z.imaginary ()) / denom;

    return new Complex (qr, qi);
  }

  /**
   * Return the string representation of this complex number.
   *
   * @return the string representation
   */
  @Override
  public String toString ()
  {
    final String operator = (m_fImaginary >= 0) ? "+" : "-";
    return m_fReal + operator + Math.abs (m_fImaginary) + "i";
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

import javax.annotation.Nonnull;

import com.helger.commons.annotation.ReturnsMutableCopy;

public class RowVector extends Matrix
{
  /**
   * Constructor.
   *
   * @param n
   *        the number of elements
   */
  public RowVector (final int n)
  {
    super (1, n);
  }

  /**
   * Constructor.
   *
   * @param values
   *        the array of values
   */
  public RowVector (final float values[])
  {
    set (values);
  }

  /**
   * Constructor.
   *
   * @param m
   *        the matrix (only the first row used)
   */
  private RowVector (final Matrix m)
  {
    _set (m);
  }

  /**
   * Return the row vector's size.
   */
  public int size ()
  {
    return m_nCols;
  }

  /**
   * Copy the values of this matrix.
   *
   * @return the copied values
   */
  @Nonnull
  @ReturnsMutableCopy
  public float [] copyValues1D ()
  {
    final float v[] = new float [m_nCols];
    for (int c = 0; c < m_nCols; ++c)
      v[c] = m_aValues[0][c];
    return v;
  }

  /**
   * Return the i'th value of the vector.
   *
   * @param i
   *        the index
   * @return the value
   */
  public float at (final int i)
  {
    return m_aValues[0][i];
  }

  // ---------//
  // Setters //
  // ---------//

  /**
   * Set this row vector from a matrix. Only the first row is used.
   *
   * @param m
   *        the matrix
   */
  private void _set (final Matrix m)
  {
    m_nRows = 1;
    m_nCols = m.m_nCols;
    m_aValues = m.m_aValues;
  }

  /**
   * Set this row vector from an array of values.
   *
   * @param values
   *        the array of values
   */
  protected void set (final float values[])
  {
    m_nRows = 1;
    m_nCols = values.length;
    m_aValues = new float [1] [];

    m_aValues[0] = values;
  }

  /**
   * Set the i'th value of the vector.
   *
   * @param i
   *        the index
   * @param value
   *        the value
   */
  public void set (final int i, final float value)
  {
    m_aValues[0][i] = value;
  }

  // -------------------//
  // Vector operations //
  // -------------------//

  /**
   * Add another row vector to this row vector.
   *
   * @param rv
   *        the other row vector
   * @return the sum row vector
   * @throws MatrixException
   *         for invalid size
   */
  public RowVector add (final RowVector rv) throws MatrixException
  {
    return new RowVector (super.add (rv));
  }

  /**
   * Subtract another row vector from this row vector.
   *
   * @param rv
   *        the other row vector
   * @return the sum row vector
   * @throws MatrixException
   *         for invalid size
   */
  public RowVector subtract (final RowVector rv) throws MatrixException
  {
    return new RowVector (super.subtract (rv));
  }

  /**
   * Compute the Euclidean norm.
   *
   * @return the norm
   */
  public float norm ()
  {
    double t = 0;
    for (int c = 0; c < m_nCols; ++c)
    {
      final float v = m_aValues[0][c];
      t += v * v;
    }

    return (float) Math.sqrt (t);
  }

  /**
   * Print the vector values.
   */
  public void print ()
  {
    for (int c = 0; c < m_nCols; ++c)
    {
      System.out.print ("  " + m_aValues[0][c]);
    }
    System.out.println ();
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

import java.io.PrintStream;

import javax.annotation.Nonnull;

import com.helger.numbercruncher.mathutils.SystemOutAlignRight;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * The matrix class.
 */
public class Matrix
{
  /** number of rows */
  protected int m_nRows;
  /** number of columns */
  protected int m_nCols;
  /** 2-d array of values */
  protected float m_aValues[][];

  // --------------//
  // Constructors //
  // --------------//

  /**
   * Default constructor.
   */
  protected Matrix ()
  {}

  /**
   * Constructor.
   *
   * @param rowCount
   *        the number of rows
   * @param colCount
   *        the number of columns
   */
  public Matrix (final int rowCount, final int colCount)
  {
    m_nRows = (rowCount > 0) ? rowCount : 1;
    m_nCols = (colCount > 0) ? colCount : 1;
    m_aValues = new float [m_nRows] [m_nCols];
  }

  /**
   * Constructor.
   *
   * @param values
   *        the 2-d array of values
   */
  public Matrix (final float [] [] values)
  {
    set (values);
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Get the row count.
   *
   * @return the row count
   */
  public int rowCount ()
  {
    return m_nRows;
  }

  /**
   * Get the column count.
   *
   * @return the column count
   */
  public int columnCount ()
  {
    return m_nCols;
  }

  /**
   * Get the value of element [r,c] in the matrix.
   *
   * @param r
   *        the row index
   * @param c
   *        the column index
   * @return the value
   * @throws MatrixException
   *         for an invalid index
   */
  public float at (final int r, final int c) throws MatrixException
  {
    if ((r < 0) || (r >= m_nRows) || (c < 0) || (c >= m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }

    return m_aValues[r][c];
  }

  /**
   * Get a row of this matrix.
   *
   * @param r
   *        the row index
   * @return the row as a row vector
   * @throws MatrixException
   *         for an invalid index
   */
  public RowVector getRow (final int r) throws MatrixException
  {
    if ((r < 0) || (r >= m_nRows))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }

    final RowVector rv = new RowVector (m_nCols);
    for (int c = 0; c < m_nCols; ++c)
    {
      rv.m_aValues[0][c] = m_aValues[r][c];
    }

    return rv;
  }

  /**
   * Get a column of this matrix.
   *
   * @param c
   *        the column index
   * @return the column as a column vector
   * @throws MatrixException
   *         for an invalid index
   */
  public ColumnVector getColumn (final int c) throws MatrixException
  {
    if ((c < 0) || (c >= m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }

    final ColumnVector cv = new ColumnVector (m_nRows);
    for (int r = 0; r < m_nRows; ++r)
    {
      cv.m_aValues[r][0] = m_aValues[r][c];
    }

    return cv;
  }

  /**
   * Copy the values of this matrix.
   *
   * @return the values
   */
  @SuppressFBWarnings ("EI_EXPOSE_REP")
  public float [] [] values ()
  {
    return m_aValues;
  }

  /**
   * Copy the values of this matrix.
   *
   * @return the copied values
   */
  public float [] [] copyValues2D ()
  {
    final float v[][] = new float [m_nRows] [m_nCols];

    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        v[r][c] = m_aValues[r][c];
      }
    }

    return v;
  }

  // ---------//
  // Setters //
  // ---------//

  /**
   * Set the value of element [r,c].
   *
   * @param r
   *        the row index
   * @param c
   *        the column index
   * @param value
   *        the value
   * @throws MatrixException
   *         for an invalid index
   */
  public void set (final int r, final int c, final float value) throws MatrixException
  {
    if ((r < 0) || (r >= m_nRows) || (c < 0) || (c >= m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }

    m_aValues[r][c] = value;
  }

  /**
   * Set this matrix from a 2-d array of values. If the rows do not have the
   * same length, then the matrix column count is the length of the shortest
   * row.
   *
   * @param values
   *        the 2-d array of values
   */
  protected void set (final float values[][])
  {
    m_nRows = values.length;
    m_nCols = values[0].length;
    m_aValues = values;

    for (int r = 1; r < m_nRows; ++r)
    {
      m_nCols = Math.min (m_nCols, values[r].length);
    }
  }

  /**
   * Set a row of this matrix from a row vector.
   *
   * @param rv
   *        the row vector
   * @param r
   *        the row index
   * @throws MatrixException
   *         for an invalid index or an invalid vector size
   */
  public void setRow (final RowVector rv, final int r) throws MatrixException
  {
    if ((r < 0) || (r >= m_nRows))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }
    if (m_nCols != rv.m_nCols)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    for (int c = 0; c < m_nCols; ++c)
    {
      m_aValues[r][c] = rv.m_aValues[0][c];
    }
  }

  /**
   * Set a column of this matrix from a column vector.
   *
   * @param cv
   *        the column vector
   * @param c
   *        the column index
   * @throws MatrixException
   *         for an invalid index or an invalid vector size
   */
  public void setColumn (final ColumnVector cv, final int c) throws MatrixException
  {
    if ((c < 0) || (c >= m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_INDEX);
    }
    if (m_nRows != cv.m_nRows)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    for (int r = 0; r < m_nRows; ++r)
    {
      m_aValues[r][c] = cv.m_aValues[r][0];
    }
  }

  // -------------------//
  // Matrix operations //
  // -------------------//

  /**
   * Return the transpose of this matrix.
   *
   * @return the transposed matrix
   */
  public Matrix transpose ()
  {
    final float tv[][] = new float [m_nCols] [m_nRows]; // transposed values

    // Set the values of the transpose.
    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        tv[c][r] = m_aValues[r][c];
      }
    }

    return new Matrix (tv);
  }

  /**
   * Add another matrix to this matrix.
   *
   * @param m
   *        the matrix addend
   * @return the sum matrix
   * @throws MatrixException
   *         for invalid size
   */
  public Matrix add (final Matrix m) throws MatrixException
  {
    // Validate m's size.
    if ((m_nRows != m.m_nRows) && (m_nCols != m.m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    final float sv[][] = new float [m_nRows] [m_nCols]; // sum values

    // Compute values of the sum.
    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        sv[r][c] = m_aValues[r][c] + m.m_aValues[r][c];
      }
    }

    return new Matrix (sv);
  }

  /**
   * Subtract another matrix from this matrix.
   *
   * @param m
   *        the matrix subrrahend
   * @return the difference matrix
   * @throws MatrixException
   *         for invalid size
   */
  public Matrix subtract (final Matrix m) throws MatrixException
  {
    // Validate m's size.
    if ((m_nRows != m.m_nRows) && (m_nCols != m.m_nCols))
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    final float dv[][] = new float [m_nRows] [m_nCols]; // difference values

    // Compute values of the difference.
    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        dv[r][c] = m_aValues[r][c] - m.m_aValues[r][c];
      }
    }

    return new Matrix (dv);
  }

  /**
   * Multiply this matrix by a constant.
   *
   * @param k
   *        the constant
   * @return the product matrix
   */
  public Matrix multiply (final float k)
  {
    final float pv[][] = new float [m_nRows] [m_nCols]; // product values

    // Compute values of the product.
    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        pv[r][c] = k * m_aValues[r][c];
      }
    }

    return new Matrix (pv);
  }

  /**
   * Multiply this matrix by another matrix.
   *
   * @param m
   *        the matrix multiplier
   * @return the product matrix
   * @throws MatrixException
   *         for invalid size
   */
  public Matrix multiply (final Matrix m) throws MatrixException
  {
    // Validate m's dimensions.
    if (m_nCols != m.m_nRows)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    final float pv[][] = new float [m_nRows] [m.m_nCols]; // product values

    // Compute values of the product.
    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m.m_nCols; ++c)
      {
        float dot = 0;
        for (int k = 0; k < m_nCols; ++k)
        {
          dot += m_aValues[r][k] * m.m_aValues[k][c];
        }
        pv[r][c] = dot;
      }
    }

    return new Matrix (pv);
  }

  /**
   * Multiply this matrix by a column vector: this*cv
   *
   * @param cv
   *        the column vector
   * @return the product column vector
   * @throws MatrixException
   *         for invalid size
   */
  public ColumnVector multiply (final ColumnVector cv) throws MatrixException
  {
    // Validate cv's size.
    if (m_nRows != cv.m_nRows)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    final float pv[] = new float [m_nRows]; // product values

    // Compute the values of the product.
    for (int r = 0; r < m_nRows; ++r)
    {
      float dot = 0;
      for (int c = 0; c < m_nCols; ++c)
      {
        dot += m_aValues[r][c] * cv.m_aValues[c][0];
      }
      pv[r] = dot;
    }

    return new ColumnVector (pv);
  }

  /**
   * Multiply a row vector by this matrix: rv*this
   *
   * @param rv
   *        the row vector
   * @return the product row vector
   * @throws MatrixException
   *         for invalid size
   */
  public RowVector multiply (final RowVector rv) throws MatrixException
  {
    // Validate rv's size.
    if (m_nCols != rv.m_nCols)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    final float pv[] = new float [m_nRows]; // product values

    // Compute the values of the product.
    for (int c = 0; c < m_nCols; ++c)
    {
      float dot = 0;
      for (int r = 0; r < m_nRows; ++r)
      {
        dot += rv.m_aValues[0][r] * m_aValues[r][c];
      }
      pv[c] = dot;
    }

    return new RowVector (pv);
  }

  /**
   * Print the matrix values.
   *
   * @param width
   *        the column width
   */
  public void print (final int width, @Nonnull final PrintStream aPS)
  {
    final SystemOutAlignRight ar = new SystemOutAlignRight (aPS);

    for (int r = 0; r < m_nRows; ++r)
    {
      ar.print ("Row ", 0);
      ar.print (r + 1, 2);
      ar.print (":", 0);

      for (int c = 0; c < m_nCols; ++c)
      {
        ar.print (m_aValues[r][c], width);
      }
      ar.println ();
    }
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import com.helger.commons.equals.EqualsHelper;

/**
 * The root finder class that implements Newton's algorithm.
 */
public class NewtonsRootFinder extends AbstractRootFinder
{
  private static final int MAX_ITERS = 50;
  private static final float TOLERANCE = 100 * Epsilon.floatValue ();

  /** x[n] value */
  private float m_fXn;
  /** x[n+1] value */
  private float m_fXnp1;
  /** previous x[n+1] value */
  private float m_fPrevXnp1;
  /** f(x[n]) */
  private float m_fFn;
  /** f(x[n+1]) */
  private float m_fFnp1;
  /** f'(x[n]) */
  private float m_fFpn;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   */
  public NewtonsRootFinder (final AbstractFunction function)
  {
    super (function, MAX_ITERS);
  }

  /**
   * Reset.
   *
   * @param x0
   *        the initial x-value
   */
  public void reset (final float x0)
  {
    super.reset ();

    m_fXnp1 = x0;
    m_fFnp1 = m_aFunction.at (m_fXnp1);
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Return the current value of x[n].
   *
   * @return the value
   */
  public float getXn ()
  {
    return m_fXn;
  }

  /**
   * Return the current value of x[n+1].
   *
   * @return the value
   */
  public float getXnp1 ()
  {
    return m_fXnp1;
  }

  /**
   * Return the current value of f(x[n]).
   *
   * @return the value
   */
  public float getFn ()
  {
    return m_fFn;
  }

  /**
   * Return the current value of f(x[n+1]).
   *
   * @return the value
   */
  public float getFnp1 ()
  {
    return m_fFnp1;
  }

  /**
   * Return the current value of f'(x[n]).
   *
   * @return the value
   */
  public float getFpn ()
  {
    return m_fFpn;
  }

  // -----------------------------//
  // RootFinder method overrides //
  // -----------------------------//

  /**
   * Do Newton's iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {
    m_fXn = m_fXnp1;
  }

  /**
   * Compute the next position of x[n+1].
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fFn = m_fFnp1;
    m_fFpn = m_aFunction.derivativeAt (m_fXn);

    // Compute the value of x[n+1].
    m_fPrevXnp1 = m_fXnp1;
    m_fXnp1 = m_fXn - m_fFn / m_fFpn;

    m_fFnp1 = m_aFunction.at (m_fXnp1);
  }

  /**
   * Check the position of x[n+1].
   *
   * @throws PositionUnchangedException
   */
  @Override
  protected void checkPosition () throws AbstractRootFinder.PositionUnchangedException
  {
    if (EqualsHelper.equals (m_fXnp1, m_fPrevXnp1))
    {
      throw new AbstractRootFinder.PositionUnchangedException ();
    }
  }

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  @Override
  protected boolean hasConverged ()
  {
    return Math.abs (m_fFnp1) < TOLERANCE;
  }
}


/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */
package org.geomajas.sld.editor.expert.gwt2.client;

import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Image;

/**
 * Custom button for the Sld Editor Toolbar.
 *
 * @author David Debuck
 *
 */
public class SldEditorToolBarButton extends Button {

	private String text;

	/**
	 * Constructor.
	 */
	public SldEditorToolBarButton() {
		super();
	}

	/**
	 * Attach an ImageResource to the button.
	 *
	 * @param imageResource imageResource
	 */
	public void setResource(ImageResource imageResource) {

		Image img = new Image(imageResource);
		DOM.insertChild(getElement(), img.getElement(), 0);

	}

	@Override
	public void setText(String text) {

		this.text = text;
		Element span = DOM.createElement("span");
		span.setInnerText(text);
		DOM.insertChild(getElement(), span, 1);

	}

	@Override
	public String getText() {

		return this.text;

	}

}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * A least-squares regression line function.
 */
public class RegressionLine implements IEvaluatable
{
  /** sum of x */
  private double m_dSumX;
  /** sum of y */
  private double m_dSumY;
  /** sum of x*x */
  private double m_dSumXX;
  /** sum of x*y */
  private double m_dSumXY;

  /** line coefficient a0 */
  private float m_fA0;
  /** line coefficient a1 */
  private float m_fA1;

  /** number of data points */
  private int m_nDataPoints;
  /** true if coefficients valid */
  private boolean m_bCoefsValid;

  /**
   * Constructor.
   */
  public RegressionLine ()
  {}

  /**
   * Constructor.
   *
   * @param data
   *        the array of data points
   */
  public RegressionLine (final DataPoint [] data)
  {
    for (final DataPoint element : data)
    {
      addDataPoint (element);
    }
  }

  /**
   * Return the current number of data points.
   *
   * @return the count
   */
  public int getDataPointCount ()
  {
    return m_nDataPoints;
  }

  /**
   * Return the coefficient a0.
   *
   * @return the value of a0
   */
  public float getA0 ()
  {
    _validateCoefficients ();
    return m_fA0;
  }

  /**
   * Return the coefficient a1.
   *
   * @return the value of a1
   */
  public float getA1 ()
  {
    _validateCoefficients ();
    return m_fA1;
  }

  /**
   * Return the sum of the x values.
   *
   * @return the sum
   */
  public double getSumX ()
  {
    return m_dSumX;
  }

  /**
   * Return the sum of the y values.
   *
   * @return the sum
   */
  public double getSumY ()
  {
    return m_dSumY;
  }

  /**
   * Return the sum of the x*x values.
   *
   * @return the sum
   */
  public double getSumXX ()
  {
    return m_dSumXX;
  }

  /**
   * Return the sum of the x*y values.
   *
   * @return the sum
   */
  public double getSumXY ()
  {
    return m_dSumXY;
  }

  /**
   * Add a new data point: Update the sums.
   *
   * @param dataPoint
   *        the new data point
   */
  public void addDataPoint (final DataPoint dataPoint)
  {
    m_dSumX += dataPoint.getX ();
    m_dSumY += dataPoint.getY ();
    m_dSumXX += dataPoint.getX () * dataPoint.getX ();
    m_dSumXY += dataPoint.getX () * dataPoint.getY ();

    ++m_nDataPoints;
    m_bCoefsValid = false;
  }

  /**
   * Return the value of the regression line function at x.
   *
   * @param x
   *        the value of x
   * @return the value of the function at x
   */
  public float at (final float x)
  {
    if (m_nDataPoints < 2)
      return Float.NaN;

    _validateCoefficients ();
    return m_fA0 + m_fA1 * x;
  }

  /**
   * Reset.
   */
  public void reset ()
  {
    m_nDataPoints = 0;
    m_dSumX = m_dSumY = m_dSumXX = m_dSumXY = 0;
    m_bCoefsValid = false;
  }

  /**
   * Validate the coefficients.
   */
  private void _validateCoefficients ()
  {
    if (m_bCoefsValid)
      return;

    if (m_nDataPoints >= 2)
    {
      final float xBar = (float) m_dSumX / m_nDataPoints;
      final float yBar = (float) m_dSumY / m_nDataPoints;

      m_fA1 = (float) ((m_nDataPoints * m_dSumXY - m_dSumX * m_dSumY) / (m_nDataPoints * m_dSumXX - m_dSumX * m_dSumX));
      m_fA0 = yBar - m_fA1 * xBar;
    }
    else
    {
      m_fA0 = m_fA1 = Float.NaN;
    }

    m_bCoefsValid = true;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * The root finder class that implements the fixed-point iteration algorithm.
 */
public class FixedPointRootFinder extends AbstractRootFinder
{
  private static final int MAX_ITERS = 50;
  private static final float TOLERANCE = 100 * Epsilon.floatValue ();

  /** x[n] value */
  private float m_fXn = Float.NaN;
  /** previous x[n] value */
  private float m_fPrevXn;
  /** g(x[n]) */
  private float m_fGn;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   */
  public FixedPointRootFinder (final AbstractFunction function)
  {
    super (function, MAX_ITERS);
  }

  /**
   * Reset.
   *
   * @param x0
   *        the initial x-value
   */
  public void reset (final float x0)
  {
    super.reset ();
    m_fGn = x0;
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Return the current value of x[n].
   *
   * @return the value
   */
  public float getXn ()
  {
    return m_fXn;
  }

  /**
   * Return the current value of g(x[n]).
   *
   * @return the value
   */
  public float getGn ()
  {
    return m_fGn;
  }

  // -----------------------------//
  // RootFinder method overrides //
  // -----------------------------//

  /**
   * Do the fixed point iteration procedure. (Nothing to do!)
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {}

  /**
   * Compute the next position of xn.
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fPrevXn = m_fXn;
    m_fXn = m_fGn;
    m_fGn = m_aFunction.at (m_fXn);
  }

  /**
   * Check the position of xn.
   *
   * @throws PositionUnchangedException
   */
  @Override
  protected void checkPosition () throws AbstractRootFinder.PositionUnchangedException
  {
    if (m_fXn == m_fPrevXn)
    {
      throw new AbstractRootFinder.PositionUnchangedException ();
    }
  }

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  @Override
  protected boolean hasConverged ()
  {
    return Math.abs ((m_fGn - m_fXn) / m_fXn) < TOLERANCE;
  }
}


/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */
package org.geomajas.sld.editor.expert.common.client.model;

import java.util.ArrayList;
import java.util.List;

import org.geomajas.sld.StyledLayerDescriptorInfo;
import org.geomajas.sld.editor.expert.common.client.domain.RawSld;
import org.geomajas.sld.editor.expert.common.client.domain.SldInfo;

/**
 * Basic implementation of SldModel.
 *
 * @author Kristof Heirwegh
 */
public class SldModelImpl implements SldModel {

	private boolean dirty;
	private boolean valid;
	private RawSld rawSld = new RawSld();
	private StyledLayerDescriptorInfo sldDescriptor;
	private RawSld template;
	private List<SldInfo> templateNames = new ArrayList<SldInfo>();

	public String getName() {
		return rawSld.getName();
	}

	/**
	 * @return true if there is a rawSld and dirty bit is set.
	 */
	public boolean isDirty() {
		return rawSld != null && dirty;
	}

	public void setDirty(boolean dirty) {
		this.dirty = dirty;
	}

	/**
	 * Valid only applies to raw data, not name or layername.
	 * <p>Only valid if not dirty & valid is set.
	 */
	public boolean isValid() {
		return valid && !dirty;
	}

	/**
	 * Setting valid will not setDirty.
	 */
	public void setValid(boolean valid) {
		this.valid = valid;
	}

	public RawSld getRawSld() {
		return rawSld;
	}

	public void setRawSld(RawSld rawSld) {
		this.rawSld = rawSld;
	}

	public String getTitle() {
		return rawSld.getTitle();
	}

	public RawSld getTemplate() {
		return template;
	}

	public void setTemplate(RawSld template) {
		this.template = template;
	}

	public List<SldInfo> getTemplateNames() {
		return templateNames;
	}

	/**
	 * Does not clear templateNames.
	 */
	public void clear() {
		rawSld = new RawSld();
		dirty = false;
		valid = false;
		template = null;
		sldDescriptor = null;
	}

	/**
	 * Will only be correct/filled in if sld has been validated/saved.
	 */
	public StyledLayerDescriptorInfo getSldDescriptor() {
		return sldDescriptor;
	}

	public void setSldDescriptor(StyledLayerDescriptorInfo sldDescriptor) {
		this.sldDescriptor = sldDescriptor;
	}
}


/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */

package org.geomajas.sld.editor.expert.common.server.service;

import java.io.File;
import java.io.FilenameFilter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.geomajas.sld.NamedLayerInfo;
import org.geomajas.sld.StyledLayerDescriptorInfo;
import org.geomajas.sld.UserLayerInfo;
import org.geomajas.sld.editor.expert.common.client.domain.RawSld;
import org.geomajas.sld.editor.expert.common.client.domain.SldInfo;
import org.geomajas.sld.editor.expert.common.client.domain.SldInfoImpl;
import org.geomajas.sld.service.SldException;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshallingContext;
import org.jibx.runtime.JiBXException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * Default implementation of the SLD service using an in-memory map. This service loads a configurable directory of SLD
 * files at startup.
 *
 * @author Jan De Moerloose
 * @author An Buyle
 */
public class InMemorySldServiceImpl implements org.geomajas.sld.editor.expert.common.server.service.SldService {

	private final Logger log = LoggerFactory.getLogger(InMemorySldServiceImpl.class);

	private static final String FILE_ENCODING = "UTF-8";

	private Map<String, RawSld> allSlds = new ConcurrentHashMap<String, RawSld>();

	private Resource directory;

	@PostConstruct
	void init() throws SldException {
		if (getDirectory() != null) {
			try {
				if (getDirectory().getFile().exists()) {
					if (getDirectory().getFile().isDirectory()) {
						File[] sldFiles = getDirectory().getFile().listFiles(new FilenameFilter() {

							public boolean accept(File dir, String name) {
								return name.endsWith(".sld") || name.endsWith(".xml");
							}
						});
						for (File file : sldFiles) {
							RawSld raw = new RawSld();
							raw.setXml(FileUtils.readFileToString(file, FILE_ENCODING));
							String fileName = StringUtils.stripFilenameExtension(file.getName());
							StyledLayerDescriptorInfo tmp = parseXml(fileName, raw.getXml());
							raw.setName(fileName);
							raw.setTitle(tmp.getTitle());
							raw.setVersion(tmp.getVersion());
							log.info("added sld '{}' to service", fileName);
							allSlds.put(raw.getName(), raw);
						}
					}
				}
			} catch (Exception e) { // NOSONAR
				log.warn("Error while initilizing SLD service.", e);
			}
		}
	}

	// ---------------------------------------------------------------

	public Resource getDirectory() {
		return directory;
	}

	public void setDirectory(Resource directory) {
		this.directory = directory;
	}

	public List<SldInfo> findTemplates() throws SldException {
		List<SldInfo> res = new ArrayList<SldInfo>();
		for (RawSld raw : allSlds.values()) {
			res.add(new SldInfoImpl(raw.getName(), raw.getTitle()));
		}
		return res;
	}

	public RawSld findTemplateByName(String name) throws SldException {
		return allSlds.get(name);
	}

	/**
	 * Convert StyledLayerDescriptorInfo to raw xml.
	 *
	 * @param sldi
	 * @return rawSld
	 * @throws SldException
	 */
	public RawSld toXml(StyledLayerDescriptorInfo sldi) throws SldException {
		try {
			if (sldi.getVersion() == null) {
				sldi.setVersion("1.0.0");
			}
			return parseSldI(sldi);
		} catch (JiBXException e) {
			throw new SldException("Validation error", e);
		}
	}

	/**
	 * Convert raw xml to StyledLayerDescriptorInfo.
	 *
	 * @param sld
	 * @return StyledLayerDescriptorInfo
	 * @throws SldException
	 */
	public StyledLayerDescriptorInfo toSldI(RawSld sld) throws SldException {
		try {
			return parseXml(sld.getName(), sld.getXml());
		} catch (JiBXException e) {
			throw new SldException("Validation error", e);
		}
	}

	/**
	 * Test by marshalling.
	 *
	 * @param sld
	 * @throws SldException
	 */
	public void validate(StyledLayerDescriptorInfo sld) throws SldException {
		try {
			parseSldI(sld);
		} catch (JiBXException e) {
			throw new SldException("Validation error", e);
		}
	}

	/**
	 * Test by unmarshalling.
	 *
	 * @param sld
	 * @throws SldException
	 */
	public boolean validate(RawSld sld) throws SldException {
		try {
			parseXml("", sld.getXml());
			return true;
		} catch (JiBXException e) {
			return false;
		}
	}

	@Override
	public RawSld format(RawSld sld) throws SldException {
		try {
			Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder()
					.parse(new InputSource(new StringReader(sld.getXml())));
			XPath xPath = XPathFactory.newInstance().newXPath();
			// we usually don't want to preserve whitespace !!!
			NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", document,
					XPathConstants.NODESET);
			for (int i = 0; i < nodeList.getLength(); ++i) {
				Node node = nodeList.item(i);
				node.getParentNode().removeChild(node);
			}
			Transformer transformer = TransformerFactory.newInstance().newTransformer();
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
			StringWriter stringWriter = new StringWriter();
			StreamResult streamResult = new StreamResult(stringWriter);
			transformer.transform(new DOMSource(document), streamResult);
			List<String> lines = IOUtils.readLines(new StringReader(stringWriter.toString()));
			// wrap the attributes of the document tag
			if (lines.size() > 1) {
				Element element = document.getDocumentElement();
				StringBuilder sb = new StringBuilder("<" + element.getNodeName());
				NamedNodeMap attributes = element.getAttributes();
				for (int i = 0; i < attributes.getLength(); i++) {
					Node attr = attributes.item(i);
					sb.append("\n    ");
					sb.append(attr.getNodeName());
					sb.append("=");
					sb.append("\"");
					sb.append(attr.getNodeValue());
					sb.append("\"");
				}
				sb.append(">");
				// replace the first line by the wrapped version
				lines.set(0, sb.toString());
			}
			RawSld res = new RawSld();
			res.setXml(StringUtils.collectionToDelimitedString(lines, "\n"));
			res.setName(sld.getName());
			res.setVersion(sld.getVersion());
			res.setTitle(sld.getTitle());
			return res;
		} catch (Exception e) {
			throw new SldException(e.getMessage());
		}
	}

	// ---------------------------------------------------------------

	private StyledLayerDescriptorInfo parseXml(String name, String raw) throws JiBXException {
		IBindingFactory bfact = BindingDirectory.getFactory(StyledLayerDescriptorInfo.class);
		IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
		Object object = uctx.unmarshalDocument(new StringReader(raw));
		StyledLayerDescriptorInfo sld = (StyledLayerDescriptorInfo) object;
		if (sld.getName() == null) {
			sld.setName(name);
		}
		if (sld.getTitle() == null) {
			sld.setTitle(getTitle(sld, name));
		}
		if (sld.getVersion() == null) {
			sld.setVersion("1.0.0");
		}
		return sld;
	}

	private RawSld parseSldI(StyledLayerDescriptorInfo sld) throws JiBXException {
		RawSld res = new RawSld();
		IBindingFactory bfact;
		bfact = BindingDirectory.getFactory(StyledLayerDescriptorInfo.class);
		IMarshallingContext mctx = bfact.createMarshallingContext();
		StringWriter writer = new StringWriter();
		mctx.setOutput(writer);
		mctx.getXmlWriter().setIndentSpaces(2, "\n", ' ');
		mctx.marshalDocument(sld);
		res.setXml(writer.toString());
		res.setName(sld.getName());
		res.setVersion(sld.getVersion());
		res.setTitle(sld.getTitle() == null ? getTitle(sld, "?") : sld.getTitle());
		return res;
	}

	private String getTitle(StyledLayerDescriptorInfo sld, String fallback) {
		if (sld.getChoiceList() != null && sld.getChoiceList().size() > 0) {
			NamedLayerInfo nli = sld.getChoiceList().get(0).getNamedLayer();
			if (nli != null && nli.getName() != null) {
				return nli.getName();
			}
			UserLayerInfo uli = sld.getChoiceList().get(0).getUserLayer();
			if (uli != null && uli.getName() != null) {
				return uli.getName();
			}
		}
		return fallback;
	}

}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Differential equation solver that implements a predictor-corrector algorithm.
 */
public class PredictorCorrectorDiffEqSolver extends AbstractDiffEqSolver
{
  /**
   * Constructor.
   *
   * @param equation
   *        the differential equation to solve
   */
  public PredictorCorrectorDiffEqSolver (final AbstractDifferentialEquation equation)
  {
    super (equation);
  }

  /**
   * Return the next data point in the approximation of the solution.
   *
   * @param h
   *        the width of the interval
   */
  @Override
  public DataPoint nextPoint (final float h)
  {
    final float predictor = m_fY + Math.abs (h) * m_aEquation.at (m_fX);
    final float avgSlope = (m_aEquation.at (m_fX, m_fY) + m_aEquation.at (m_fX + h, predictor)) / 2;

    m_fY += h * avgSlope; // corrector
    m_fX += h;

    return new DataPoint (m_fX, m_fY);
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Function integrator that implements the trapezoidal algorithm.
 */
public class TrapezoidalIntegrator implements IIntegrator
{
  /** the function to integrate */
  private final IEvaluatable m_aIntegrand;

  /**
   * Constructor.
   *
   * @param integrand
   *        the function to integrate
   */
  public TrapezoidalIntegrator (final IEvaluatable integrand)
  {
    this.m_aIntegrand = integrand;
  }

  /**
   * Integrate the function from a to b using the trapezoidal algorithm, and
   * return an approximation to the area. (Integrator implementation.)
   *
   * @param a
   *        the lower limit
   * @param b
   *        the upper limit
   * @param intervals
   *        the number of equal-width intervals
   * @return an approximation to the area
   */
  public float integrate (final float a, final float b, final int intervals)
  {
    if (b <= a)
      return 0;

    final float h = (b - a) / intervals; // interval width
    float totalArea = 0;

    // Compute the area using the current number of intervals.
    for (int i = 0; i < intervals; ++i)
    {
      final float x1 = a + i * h;
      totalArea += _areaOf (x1, h);
    }

    return totalArea;
  }

  /**
   * Compute the area of the ith trapezoidal region.
   *
   * @param x1
   *        the left bound of the region
   * @param h
   *        the interval width
   * @return the area of the region
   */
  private float _areaOf (final float x1, final float h)
  {
    final float x2 = x1 + h; // right bound of the region
    final float y1 = m_aIntegrand.at (x1); // value at left bound
    final float y2 = m_aIntegrand.at (x2); // value at right bound
    final float area = h * (y1 + y2) / 2; // area of the region

    return area;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

/**
 * A square matrix.
 */
public class SquareMatrix extends Matrix
{
  // --------------//
  // Constructors //
  // --------------//

  /**
   * Constructor.
   *
   * @param n
   *        the number of rows == the number of columns
   */
  public SquareMatrix (final int n)
  {
    super (n, n);
  }

  /**
   * Constructor.
   *
   * @param m
   *        the matrix (only the upper left square used)
   */
  private SquareMatrix (final Matrix m)
  {
    _set (m);
  }

  /**
   * Constructor.
   *
   * @param values
   *        the array of values
   */
  public SquareMatrix (final float values[][])
  {
    set (values);
  }

  // ---------//
  // Setters //
  // ---------//

  /**
   * Set this square matrix from another matrix. Note that this matrix will
   * reference the values of the argument matrix. If the values are not square,
   * only the upper left square is used.
   *
   * @param m
   *        the 2-d array of values
   */
  private void _set (final Matrix m)
  {
    this.m_nRows = this.m_nCols = Math.min (m.m_nRows, m.m_nCols);
    this.m_aValues = m.m_aValues;
  }

  /**
   * Set this square matrix from a 2-d array of values. If the values are not
   * square, only the upper left square is used.
   *
   * @param values
   *        the 2-d array of values
   */
  @Override
  protected void set (final float values[][])
  {
    super.set (values);
    m_nRows = m_nCols = Math.min (m_nRows, m_nCols);
  }

  // -------------------//
  // Matrix operations //
  // -------------------//

  /**
   * Add another square matrix to this matrix.
   *
   * @param sm
   *        the square matrix addend
   * @return the sum matrix
   * @throws MatrixException
   *         for invalid size
   */
  public SquareMatrix add (final SquareMatrix sm) throws MatrixException
  {
    return new SquareMatrix (super.add (sm));
  }

  /**
   * Subtract another square matrix from this matrix.
   *
   * @param sm
   *        the square matrix subrrahend
   * @return the difference matrix
   * @throws MatrixException
   *         for invalid size
   */
  public SquareMatrix subtract (final SquareMatrix sm) throws MatrixException
  {
    return new SquareMatrix (super.subtract (sm));
  }

  /**
   * Multiply this square matrix by another square matrix.
   *
   * @param sm
   *        the square matrix multiplier
   * @return the product matrix
   * @throws MatrixException
   *         for invalid size
   */
  public SquareMatrix multiply (final SquareMatrix sm) throws MatrixException
  {
    return new SquareMatrix (super.multiply (sm));
  }
}


/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */
package org.geomajas.sld.editor.expert.common.client.event;

import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HasHandlers;
import com.google.web.bindery.event.shared.HandlerRegistration;

/**
 * Event fired when the user wants to close the current SLD. It has an additional option to save the current
 * SLD before closing {@link #fireSave(HasHandlers)}.
 *
 * @author Jan De Moerloose
 *
 */
public class SldCloseEvent extends GwtEvent<SldCloseEvent.SldCloseHandler> {

	private boolean save;

	public SldCloseEvent(boolean save) {
		this.save = save;
	}

	public boolean isSave() {
		return save;
	}

	/**
	 * Fires a {@link SldCloseEvent} that will save the current SLD and close it. If not successful, the current SLD
	 * remains open.
	 *
	 * @param source
	 * @param name
	 */
	public static void fireSave(HasHandlers source) {
		SldCloseEvent eventInstance = new SldCloseEvent(true);
		source.fireEvent(eventInstance);
	}

	/**
	 * Fires a {@link SldCloseEvent} that will close the current SLD regardless of changes.
	 *
	 * @param source
	 * @param name
	 */
	public static void fire(HasHandlers source) {
		SldCloseEvent eventInstance = new SldCloseEvent(false);
		source.fireEvent(eventInstance);
	}

	public static void fire(HasHandlers source, SldCloseEvent eventInstance) {
		source.fireEvent(eventInstance);
	}

	/**
	 * {@link HasHandlers} indicator for this event.
	 *
	 * @author Jan De Moerloose
	 *
	 */
	public interface HasSldCloseHandlers extends HasHandlers {

		HandlerRegistration addSldCloseHandler(SldCloseHandler handler);
	}

	/**
	 * {@link EventHandler} interface for this event.
	 *
	 * @author Jan De Moerloose
	 *
	 */
	public interface SldCloseHandler extends EventHandler {

		/**
		 * Notifies side content child presenter to reveal itself.
		 *
		 * @param event the event
		 */
		void onSldClose(SldCloseEvent event);
	}

	private static final Type<SldCloseHandler> TYPE = new Type<SldCloseHandler>();

	public static Type<SldCloseHandler> getType() {
		return TYPE;
	}

	@Override
	public Type<SldCloseHandler> getAssociatedType() {
		return TYPE;
	}

	@Override
	protected void dispatch(SldCloseHandler handler) {
		handler.onSldClose(this);
	}

	@Override
	public boolean equals(Object obj) {
		return super.equals(obj);
	}

	@Override
	public int hashCode() {
		return super.hashCode();
	}

	@Override
	public String toString() {
		return "SldCloseEvent[" + "]";
	}

}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

/**
 * A matrix that can be inverted. Also, compute its determinant, norm, and
 * condition number.
 */
public class InvertibleMatrix extends LinearSystem
{
  /**
   * Constructor.
   *
   * @param n
   *        the number of rows = the number of columns
   */
  public InvertibleMatrix (final int n)
  {
    super (n);
  }

  /**
   * Constructor.
   *
   * @param values
   *        the array of values
   */
  public InvertibleMatrix (final float values[][])
  {
    super (values);
  }

  /**
   * Compute the inverse of this matrix.
   *
   * @return the inverse matrix
   * @throws MatrixException
   *         if an error occurred
   */
  public InvertibleMatrix inverse () throws MatrixException
  {
    final InvertibleMatrix inverse = new InvertibleMatrix (m_nRows);
    final IdentityMatrix identity = new IdentityMatrix (m_nRows);

    // Compute each column of the inverse matrix
    // using columns of the identity matrix.
    for (int c = 0; c < m_nCols; ++c)
    {
      final ColumnVector col = solve (identity.getColumn (c), true);
      inverse.setColumn (col, c);
    }

    return inverse;
  }

  /**
   * Compute the determinant.
   *
   * @return the determinant
   * @throws MatrixException
   *         if an error occurred
   */
  public float determinant () throws MatrixException
  {
    decompose ();

    // Each row exchange during forward elimination flips the sign
    // of the determinant, so check for an odd number of exchanges.
    float determinant = ((m_nExchangeCount & 1) == 0) ? 1 : -1;

    // Form the product of the diagonal elements of matrix U.
    for (int i = 0; i < m_nRows; ++i)
    {
      final int pi = m_aPermutation[i]; // permuted index
      determinant *= m_aLU.at (pi, i);
    }

    return determinant;
  }

  /**
   * Compute the Euclidean norm of this matrix.
   *
   * @return the norm
   */
  public float norm ()
  {
    float sum = 0;

    for (int r = 0; r < m_nRows; ++r)
    {
      for (int c = 0; c < m_nCols; ++c)
      {
        final float v = m_aValues[r][c];
        sum += v * v;
      }
    }

    return (float) Math.sqrt (sum);
  }

  /**
   * Compute the condition number based on the Euclidean norm.
   *
   * @return the condition number
   */
  public float condition () throws MatrixException
  {
    return norm () * inverse ().norm ();
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

import java.io.PrintStream;

import javax.annotation.Nonnull;

import com.helger.numbercruncher.mathutils.Epsilon;
import com.helger.numbercruncher.mathutils.SystemOutAlignRight;

/**
 * Solve a system of linear equations using LU decomposition.
 */
public class LinearSystem extends SquareMatrix
{
  private static final float TOLERANCE = Epsilon.floatValue ();

  /** max iters for improvement = twice # of significant digits */
  private static final int MAX_ITER;

  static
  {
    int i = 0;
    float t = TOLERANCE;
    while (t < 1)
    {
      ++i;
      t *= 10;
    }
    MAX_ITER = 2 * i;
  }

  /** decomposed matrix A = LU */
  protected SquareMatrix m_aLU;
  /** row index permutation vector */
  protected int [] m_aPermutation;
  /** row exchange count */
  protected int m_nExchangeCount;

  /**
   * Constructor.
   *
   * @param n
   *        the number of rows = the number of columns
   */
  public LinearSystem (final int n)
  {
    super (n);
    reset ();
  }

  /**
   * Constructor.
   *
   * @param values
   *        the array of values
   */
  public LinearSystem (final float values[][])
  {
    super (values);
  }

  /**
   * Set the values of the matrix.
   *
   * @param values
   *        the 2-d array of values
   */
  @Override
  protected void set (final float values[][])
  {
    super.set (values);
    reset ();
  }

  /**
   * Set the value of element [r,c] in the matrix.
   *
   * @param r
   *        the row index, 0..nRows
   * @param c
   *        the column index, 0..nRows
   * @param value
   *        the value
   * @throws MatrixException
   *         for invalid index
   */
  @Override
  public void set (final int r, final int c, final float value) throws MatrixException
  {
    super.set (r, c, value);
    reset ();
  }

  /**
   * Set a row of this matrix from a row vector.
   *
   * @param rv
   *        the row vector
   * @param r
   *        the row index
   * @throws MatrixException
   *         for an invalid index or an invalid vector size
   */
  @Override
  public void setRow (final RowVector rv, final int r) throws MatrixException
  {
    super.setRow (rv, r);
    reset ();
  }

  /**
   * Set a column of this matrix from a column vector.
   *
   * @param cv
   *        the column vector
   * @param c
   *        the column index
   * @throws MatrixException
   *         for an invalid index or an invalid vector size
   */
  @Override
  public void setColumn (final ColumnVector cv, final int c) throws MatrixException
  {
    super.setColumn (cv, c);
    reset ();
  }

  /**
   * Reset. Invalidate LU and the permutation vector.
   */
  protected void reset ()
  {
    m_aLU = null;
    m_aPermutation = null;
    m_nExchangeCount = 0;
  }

  /**
   * Solve Ax = b for x using the Gaussian elimination algorithm.
   *
   * @param b
   *        the right-hand-side column vector
   * @param improve
   *        true to improve the solution
   * @return the solution column vector
   * @throws MatrixException
   *         if an error occurred
   */
  public ColumnVector solve (final ColumnVector b, final boolean improve) throws MatrixException
  {
    // Validate b's size.
    if (b.m_nRows != m_nRows)
    {
      throw new MatrixException (MatrixException.INVALID_DIMENSIONS);
    }

    decompose ();

    // Solve Ly = b for y by forward substitution.
    // Solve Ux = y for x by back substitution.
    final ColumnVector y = _forwardSubstitution (b);
    final ColumnVector x = _backSubstitution (y);

    // Improve and return x.
    if (improve)
      _improve (b, x);
    return x;
  }

  /**
   * Print the decomposed matrix LU.
   *
   * @param width
   *        the column width
   * @throws MatrixException
   *         if an error occurred
   */
  public void printDecomposed (final int width, @Nonnull final PrintStream aPS) throws MatrixException
  {
    decompose ();

    final SystemOutAlignRight ar = new SystemOutAlignRight (aPS);

    for (int r = 0; r < m_nRows; ++r)
    {
      final int pr = m_aPermutation[r]; // permuted row index
      ar.print ("Row ", 0);
      ar.print (r + 1, 2);
      ar.print (":", 0);

      for (int c = 0; c < m_nCols; ++c)
      {
        ar.print (m_aLU.m_aValues[pr][c], width);
      }
      ar.println ();
    }
  }

  /**
   * Compute the upper triangular matrix U and lower triangular matrix L such
   * that A = L*U. Store L and U together in matrix LU. Compute the permutation
   * vector permutation of the row indices.
   *
   * @throws MatrixException
   *         for a zero row or a singular matrix
   */
  protected void decompose () throws MatrixException
  {
    // Return if the decomposition is valid.
    if (m_aLU != null)
      return;

    // Create a new LU matrix and permutation vector.
    // LU is initially just a copy of the values of this system.
    m_aLU = new SquareMatrix (this.copyValues2D ());
    m_aPermutation = new int [m_nRows];

    final float scales[] = new float [m_nRows];

    // Loop to initialize the permutation vector and scales.
    for (int r = 0; r < m_nRows; ++r)
    {
      m_aPermutation[r] = r; // initially no row exchanges

      // Find the largest row element.
      float largestRowElmt = 0;
      for (int c = 0; c < m_nRows; ++c)
      {
        final float elmt = Math.abs (m_aLU.at (r, c));
        if (largestRowElmt < elmt)
          largestRowElmt = elmt;
      }

      // Set the scaling factor for row equilibration.
      if (largestRowElmt != 0)
      {
        scales[r] = 1 / largestRowElmt;
      }
      else
      {
        throw new MatrixException (MatrixException.ZERO_ROW);
      }
    }

    // Do forward elimination with scaled partial row pivoting.
    _forwardElimination (scales);

    // Check bottom right element of the permuted matrix.
    if (m_aLU.at (m_aPermutation[m_nRows - 1], m_nRows - 1) == 0)
    {
      throw new MatrixException (MatrixException.SINGULAR);
    }
  }

  /**
   * Do forward elimination with scaled partial row pivoting.
   *
   * @parm scales the scaling vector
   * @throws MatrixException
   *         for a singular matrix
   */
  private void _forwardElimination (final float scales[]) throws MatrixException
  {
    // Loop once per pivot row 0..nRows-1.
    for (int rPivot = 0; rPivot < m_nRows - 1; ++rPivot)
    {
      float largestScaledElmt = 0;
      int rLargest = 0;

      // Starting from the pivot row rPivot, look down
      // column rPivot to find the largest scaled element.
      for (int r = rPivot; r < m_nRows; ++r)
      {

        // Use the permuted row index.
        final int pr = m_aPermutation[r];
        final float absElmt = Math.abs (m_aLU.at (pr, rPivot));
        final float scaledElmt = absElmt * scales[pr];

        if (largestScaledElmt < scaledElmt)
        {

          // The largest scaled element and
          // its row index.
          largestScaledElmt = scaledElmt;
          rLargest = r;
        }
      }

      // Is the matrix singular?
      if (largestScaledElmt == 0)
      {
        throw new MatrixException (MatrixException.SINGULAR);
      }

      // Exchange rows if necessary to choose the best
      // pivot element by making its row the pivot row.
      if (rLargest != rPivot)
      {
        final int temp = m_aPermutation[rPivot];
        m_aPermutation[rPivot] = m_aPermutation[rLargest];
        m_aPermutation[rLargest] = temp;

        ++m_nExchangeCount;
      }

      // Use the permuted pivot row index.
      final int prPivot = m_aPermutation[rPivot];
      final float pivotElmt = m_aLU.at (prPivot, rPivot);

      // Do the elimination below the pivot row.
      for (int r = rPivot + 1; r < m_nRows; ++r)
      {

        // Use the permuted row index.
        final int pr = m_aPermutation[r];
        final float multiple = m_aLU.at (pr, rPivot) / pivotElmt;

        // Set the multiple into matrix L.
        m_aLU.set (pr, rPivot, multiple);

        // Eliminate an unknown from matrix U.
        if (multiple != 0)
        {
          for (int c = rPivot + 1; c < m_nCols; ++c)
          {
            float elmt = m_aLU.at (pr, c);

            // Subtract the multiple of the pivot row.
            elmt -= multiple * m_aLU.at (prPivot, c);
            m_aLU.set (pr, c, elmt);
          }
        }
      }
    }
  }

  /**
   * Solve Ly = b for y by forward substitution.
   *
   * @param b
   *        the column vector b
   * @return the column vector y
   * @throws MatrixException
   *         if an error occurred
   */
  private ColumnVector _forwardSubstitution (final ColumnVector b) throws MatrixException
  {
    final ColumnVector y = new ColumnVector (m_nRows);

    // Do forward substitution.
    for (int r = 0; r < m_nRows; ++r)
    {
      final int pr = m_aPermutation[r]; // permuted row index
      float dot = 0;
      for (int c = 0; c < r; ++c)
      {
        dot += m_aLU.at (pr, c) * y.at (c);
      }
      y.set (r, b.at (pr) - dot);
    }

    return y;
  }

  /**
   * Solve Ux = y for x by back substitution.
   *
   * @param y
   *        the column vector y
   * @return the solution column vector x
   * @throws MatrixException
   *         if an error occurred
   */
  private ColumnVector _backSubstitution (final ColumnVector y) throws MatrixException
  {
    final ColumnVector x = new ColumnVector (m_nRows);

    // Do back substitution.
    for (int r = m_nRows - 1; r >= 0; --r)
    {
      final int pr = m_aPermutation[r]; // permuted row index
      float dot = 0;
      for (int c = r + 1; c < m_nRows; ++c)
      {
        dot += m_aLU.at (pr, c) * x.at (c);
      }
      x.set (r, (y.at (r) - dot) / m_aLU.at (pr, r));
    }

    return x;
  }

  /**
   * Iteratively improve the solution x to machine accuracy.
   *
   * @param b
   *        the right-hand side column vector
   * @param x
   *        the improved solution column vector
   * @throws MatrixException
   *         if failed to converge
   */
  private void _improve (final ColumnVector b, final ColumnVector x) throws MatrixException
  {
    // Find the largest x element.
    float largestX = 0;
    for (int r = 0; r < m_nRows; ++r)
    {
      final float absX = Math.abs (x.m_aValues[r][0]);
      if (largestX < absX)
        largestX = absX;
    }

    // Is x already as good as possible?
    if (largestX == 0)
      return;

    final ColumnVector residuals = new ColumnVector (m_nRows);

    // Iterate to improve x.
    for (int iter = 0; iter < MAX_ITER; ++iter)
    {

      // Compute residuals = b - Ax.
      // Must use double precision!
      for (int r = 0; r < m_nRows; ++r)
      {
        double dot = 0;
        for (int c = 0; c < m_nRows; ++c)
        {
          final double elmt = at (r, c);
          dot += elmt * x.at (c); // dbl.prec. *
        }
        final double value = b.at (r) - dot; // dbl.prec. -
        residuals.set (r, (float) value);
      }

      // Solve Az = residuals for z.
      final ColumnVector z = solve (residuals, false);

      // Set x = x + z.
      // Find largest the largest difference.
      float largestDiff = 0;
      for (int r = 0; r < m_nRows; ++r)
      {
        final float oldX = x.at (r);
        x.set (r, oldX + z.at (r));

        final float diff = Math.abs (x.at (r) - oldX);
        if (largestDiff < diff)
          largestDiff = diff;
      }

      // Is any further improvement possible?
      if (largestDiff < largestX * TOLERANCE)
        return;
    }

    // Failed to converge because A is nearly singular.
    throw new MatrixException (MatrixException.NO_CONVERGENCE);
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.matrix;

public class IdentityMatrix extends SquareMatrix
{
  /**
   * Constructor.
   *
   * @param n
   *        the number of rows == the number of columns
   */
  public IdentityMatrix (final int n)
  {
    super (n);
    for (int i = 0; i < n; ++i)
      m_aValues[i][i] = 1;
  }

  /**
   * Convert a square matrix into an identity matrix.
   *
   * @param sm
   *        the square matrix to convert
   */
  public static void convert (final SquareMatrix sm)
  {
    for (int r = 0; r < sm.m_nRows; ++r)
    {
      for (int c = 0; c < sm.m_nCols; ++c)
      {
        sm.m_aValues[r][c] = (r == c) ? 1 : 0;
      }
    }
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import java.util.Random;

/**
 * Utility class that generates exponentially-distributed random values using
 * several algorithms.
 */
public class RandomExponential
{
  private float m_fMean;

  /** generator of uniformly-distributed random values */
  private static final Random GENERATOR = new Random ();

  /**
   * Set the mean.
   *
   * @param mean
   *        the mean
   */
  public void setParameters (final float mean)
  {
    this.m_fMean = mean;
  }

  /**
   * Compute the next randomn value using the logarithm algorithm. Requires a
   * uniformly-distributed random value in [0, 1).
   */
  public float nextLog ()
  {
    // Generate a non-zero uniformly-distributed random value.
    float u;
    while ((u = GENERATOR.nextFloat ()) == 0)
    {
      // try again if 0
    }

    return (float) (-m_fMean * Math.log (u));
  }

  /**
   * Compute the next randomn value using the von Neumann algorithm. Requires
   * sequences of uniformly-distributed random values in [0, 1).
   */
  public float nextVonNeumann ()
  {
    int n;
    int k = 0;
    float u1;

    // Loop to try sequences of uniformly-distributed
    // random values.
    for (;;)
    {
      n = 1;
      u1 = GENERATOR.nextFloat ();

      float u = u1;
      float uPrev = Float.NaN;

      // Loop to generate a sequence of ramdom values
      // as long as they are decreasing.
      for (;;)
      {
        uPrev = u;
        u = GENERATOR.nextFloat ();

        // No longer decreasing?
        if (u > uPrev)
        {

          // n is even.
          if ((n & 1) == 0)
          {
            return u1 + k; // return a random value
          }

          // n is odd.
          ++k;
          break; // try another sequence
        }

        ++n;
      }
    }
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Differential equation solver that implements a fourth-order Runge-Kutta
 * algorithm.
 */
public class RungeKuttaDiffEqSolver extends AbstractDiffEqSolver
{
  /**
   * Constructor.
   *
   * @param equation
   *        the differential equation to solve
   */
  public RungeKuttaDiffEqSolver (final AbstractDifferentialEquation equation)
  {
    super (equation);
  }

  /**
   * Return the next data point in the approximation of the solution.
   *
   * @param h
   *        the width of the interval
   */
  @Override
  public DataPoint nextPoint (final float h)
  {
    final float k1 = m_aEquation.at (m_fX, m_fY);
    final float k2 = m_aEquation.at (m_fX + h / 2, m_fY + k1 * h / 2);
    final float k3 = m_aEquation.at (m_fX + h / 2, m_fY + k2 * h / 2);
    final float k4 = m_aEquation.at (m_fX + h, m_fY + k3 * h);

    m_fY += (k1 + 2 * (k2 + k3) + k4) * h / 6;
    m_fX += h;

    return new DataPoint (m_fX, m_fY);
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import com.helger.commons.equals.EqualsHelper;

/**
 * The root finder class that implements the regula falsi algorithm.
 */
public class RegulaFalsiRootFinder extends AbstractRootFinder
{
  private static final int MAX_ITERS = 50;
  private static final float TOLERANCE = 100 * Epsilon.floatValue ();

  /** x-negative value */
  protected float m_fXNeg;
  /** x-false value */
  protected float m_fXFalse = Float.NaN;
  /** x-positive value */
  protected float m_fXPos;
  /** previous x-false value */
  protected float m_fPrevXFalse;
  /** f(xNeg) */
  protected float m_fNeg;
  /** f(xFalse) */
  protected float m_fFalse = Float.NaN;
  /** f(xPos) */
  protected float m_fPos;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   * @param xMin
   *        the initial x-value where the function is negative
   * @param xMax
   *        the initial x-value where the function is positive
   * @throws AbstractRootFinder.InvalidIntervalException
   */
  public RegulaFalsiRootFinder (final AbstractFunction function,
                                final float xMin,
                                final float xMax) throws AbstractRootFinder.InvalidIntervalException
  {
    super (function, MAX_ITERS);
    checkInterval (xMin, xMax);

    final float yMin = function.at (xMin);
    final float yMax = function.at (xMax);

    // Initialize xNeg, fNeg, xPos, and fPos.
    if (yMin < 0)
    {
      m_fXNeg = xMin;
      m_fXPos = xMax;
      m_fNeg = yMin;
      m_fPos = yMax;
    }
    else
    {
      m_fXNeg = xMax;
      m_fXPos = xMin;
      m_fNeg = yMax;
      m_fPos = yMin;
    }
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Return the current value of x-negative.
   *
   * @return the value
   */
  public float getXNeg ()
  {
    return m_fXNeg;
  }

  /**
   * Return the current value of x-false.
   *
   * @return the value
   */
  public float getXFalse ()
  {
    return m_fXFalse;
  }

  /**
   * Return the current value of x-positive.
   *
   * @return the value
   */
  public float getXPos ()
  {
    return m_fXPos;
  }

  /**
   * Return the current value of f(x-negative).
   *
   * @return the value
   */
  public float getFNeg ()
  {
    return m_fNeg;
  }

  /**
   * Return the current value of f(x-false).
   *
   * @return the value
   */
  public float getFFalse ()
  {
    return m_fFalse;
  }

  /**
   * Return the current value of f(x-positive).
   *
   * @return the value
   */
  public float getFPos ()
  {
    return m_fPos;
  }

  // -----------------------------//
  // RootFinder method overrides //
  // -----------------------------//

  /**
   * Do the regula falsi iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {
    if (n == 1)
      return; // already initialized

    if (m_fFalse < 0)
    {
      m_fXNeg = m_fXFalse; // the root is in the xPos side
      m_fNeg = m_fFalse;
    }
    else
    {
      m_fXPos = m_fXFalse; // the root is in the xNeg side
      m_fPos = m_fFalse;
    }
  }

  /**
   * Compute the next position of x-false.
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fPrevXFalse = m_fXFalse;
    m_fXFalse = m_fXPos - m_fPos * (m_fXNeg - m_fXPos) / (m_fNeg - m_fPos);
    m_fFalse = m_aFunction.at (m_fXFalse);
  }

  /**
   * Check the position of x-false.
   *
   * @throws PositionUnchangedException
   */
  @Override
  protected void checkPosition () throws AbstractRootFinder.PositionUnchangedException
  {
    if (EqualsHelper.equals (m_fXFalse, m_fPrevXFalse))
    {
      throw new AbstractRootFinder.PositionUnchangedException ();
    }
  }

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  @Override
  protected boolean hasConverged ()
  {
    return Math.abs (m_fFalse) < TOLERANCE;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * The root finder class that implements the improved regula falsi algorithm.
 */
public class ImprovedRegulaFalsiRootFinder extends RegulaFalsiRootFinder
{
  /** previous f(xFalse) value */
  private float m_fPrevFFalse;

  private boolean m_bDecreasePos = false;
  private boolean m_bDecreaseNeg = false;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   * @param xMin
   *        the initial x-value where the function is negative
   * @param xMax
   *        the initial x-value where the function is positive
   * @throws AbstractRootFinder.InvalidIntervalException
   */
  public ImprovedRegulaFalsiRootFinder (final AbstractFunction function,
                                        final float xMin,
                                        final float xMax) throws AbstractRootFinder.InvalidIntervalException
  {
    super (function, xMin, xMax);
  }

  // ----------------------------------------//
  // Override RegulaFalsiRootFinder methods //
  // ----------------------------------------//

  /**
   * Do the improved regula falsi iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {
    super.doIterationProcedure (n);

    // Decrease the slope of the secant?
    if (m_bDecreasePos)
      m_fPos /= 2;
    if (m_bDecreaseNeg)
      m_fNeg /= 2;
  }

  /**
   * Compute the next position of xFalse.
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fPrevXFalse = m_fXFalse;
    m_fPrevFFalse = m_fFalse;
    m_fXFalse = m_fXPos - m_fPos * (m_fXNeg - m_fXPos) / (m_fNeg - m_fPos);
    m_fFalse = m_aFunction.at (m_fXFalse);

    m_bDecreasePos = m_bDecreaseNeg = false;

    // If there was no sign change in f(xFalse),
    // or if this is the first iteration step,
    // then decrease the slope of the secant.
    if (Float.isNaN (m_fPrevFFalse) || (m_fPrevFFalse * m_fFalse > 0))
    {
      if (m_fFalse < 0)
        m_bDecreasePos = true;
      else
        m_bDecreaseNeg = true;
    }
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Abstract base class for the root finder classes.
 */
public abstract class AbstractRootFinder
{
  /** the function whose roots to find */
  protected AbstractFunction m_aFunction;
  /** iteration counter */
  private int m_nIndex;
  /** maximum number of iterations */
  private final int m_nMaxIters;

  /**
   * Constructor.
   *
   * @param function
   *        the function whose roots to find
   * @param maxIters
   *        the maximum number of iterations
   */
  public AbstractRootFinder (final AbstractFunction function, final int maxIters)
  {
    m_aFunction = function;
    m_nMaxIters = maxIters;
  }

  /**
   * Check the interval.
   *
   * @param x1
   *        x-coordinate of the left of the interval
   * @param x2
   *        x-coordinate of the right end of the interval
   * @throws InvalidIntervalException
   */
  public void checkInterval (final float x1, final float x2) throws InvalidIntervalException
  {
    final float y1 = m_aFunction.at (x1);
    final float y2 = m_aFunction.at (x2);

    // The interval is invalid if y1 and y2 have the same signs.
    if (y1 * y2 > 0)
      throw new InvalidIntervalException ();
  }

  /**
   * Return the iteration count.
   *
   * @return the count
   */
  public int getIterationCount ()
  {
    return m_nIndex;
  }

  /**
   * Perform one iteration step.
   *
   * @return true if the algorithm converged, else false
   * @throws IterationCountExceededException
   * @throws PositionUnchangedException
   */
  public boolean step () throws IterationCountExceededException, PositionUnchangedException
  {
    checkIterationCount ();
    doIterationProcedure (m_nIndex);

    computeNextPosition ();
    checkPosition ();

    return hasConverged ();
  }

  /**
   * Check the iteration count to see if it has exeeded the maximum number of
   * iterations.
   *
   * @throws IterationCountExceededException
   */
  protected void checkIterationCount () throws IterationCountExceededException
  {
    if (++m_nIndex > m_nMaxIters)
    {
      throw new IterationCountExceededException ();
    }
  }

  /**
   * Reset.
   */
  protected void reset ()
  {
    m_nIndex = 0;
  }

  // ------------------//
  // Subclass methods //
  // ------------------//

  /**
   * Do the iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  protected abstract void doIterationProcedure (int n);

  /**
   * Compute the next position of x.
   */
  protected abstract void computeNextPosition ();

  /**
   * Check the position of x.
   *
   * @throws PositionUnchangedException
   */
  protected abstract void checkPosition () throws PositionUnchangedException;

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  protected abstract boolean hasConverged ();

  // ------------------------//
  // Root finder exceptions //
  // ------------------------//

  /**
   * Invalid interval exception.
   */
  public static class InvalidIntervalException extends Exception
  {}

  /**
   * Iteration count exceeded exception.
   */
  public static class IterationCountExceededException extends Exception
  {}

  /**
   * Position unchanged exception.
   */
  public static class PositionUnchangedException extends Exception
  {}
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Implement Kahan's Summation Algorithm for the float type.
 */
public class KahanSummation
{
  /** the current running sum */
  private float m_fSum;
  /** the current correction */
  private float m_fCorrection;
  /** the current corrected added */
  private float m_fCorrectedAddend;

  /**
   * Constructor.
   */
  public KahanSummation ()
  {}

  /**
   * Return the current corrected value of the running sum.
   *
   * @return the running sum's value
   */
  public float value ()
  {
    return m_fSum + m_fCorrection;
  }

  /**
   * Return the corrected value of the current addend.
   *
   * @return the corrected addend value
   */
  public float correctedAddend ()
  {
    return m_fCorrectedAddend;
  }

  /**
   * Add the value of an addend to the running sum.
   *
   * @param addend
   *        the value
   */
  public void add (final float addend)
  {
    // Correct the addend value and add it to the running sum.
    m_fCorrectedAddend = addend + m_fCorrection;
    final float tempSum = m_fSum + m_fCorrectedAddend;

    // Compute the next correction and set the running sum.
    // The parentheses are necessary to compute the high-order
    // bits of the addend.
    m_fCorrection = m_fCorrectedAddend - (tempSum - m_fSum);
    m_fSum = tempSum;
  }

  /**
   * Clear the running sum and the correction.
   */
  public void clear ()
  {
    m_fSum = 0;
    m_fCorrection = 0;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

/**
 * Perform multiplication and exponentiation modulo arithmetic.
 */
public class ModuloArithmetic
{
  /**
   * Multiply two integer values a and b modulo m.
   *
   * @param pa
   *        the value of a
   * @param pb
   *        the value of b
   * @param m
   *        the modulus m
   * @return the value of ab (mod m)
   */
  public static int multiply (final int pa, final int pb, final int m)
  {
    int a = pa;
    int b = pb;
    int product = 0;

    // Loop to compute product = (a*b)%m.
    while (a > 0)
    {

      // Does the rightmost bit of a == 1?
      if ((a & 1) == 1)
      {
        product += b;
        product %= m;
      }

      // Double b modulo m, and
      // shift a 1 bit to the right.
      b <<= 1;
      b %= m;
      a >>= 1;
    }

    return product;
  }

  /**
   * Raise a to the b power modulo m.
   *
   * @param pbase
   *        the value of a
   * @param pexponent
   *        the value of b
   * @param m
   *        the modulus m
   * @return the value of a^b (mod m)
   */
  public static int raise (final int pbase, final int pexponent, final int m)
  {
    int base = pbase;
    int exponent = pexponent;
    int power = 1;

    // Loop to compute power = (base^exponent)%m.
    while (exponent > 0)
    {

      // Does the rightmost bit of the exponent == 1?
      if ((exponent & 1) == 1)
      {
        power = multiply (power, base, m);
      }

      // Square the base modulo m and
      // shift the exponent 1 bit to the right.
      base = multiply (base, base, m);
      exponent >>= 1;
    }

    return power;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import com.helger.commons.equals.EqualsHelper;

/**
 * The root finder class that implements the secant algorithm.
 */
public class SecantRootFinder extends AbstractRootFinder
{
  private static final int MAX_ITERS = 50;
  private static final float TOLERANCE = 100 * Epsilon.floatValue ();

  /** x[n-1] value */
  private float m_fXnm1;
  /** x[n] value */
  private float m_fXn;
  /** x[n+1] value */
  private float m_fXnp1 = Float.NaN;
  /** previous value of x[n+1] */
  private float m_fPrevXnp1;
  /** f(x[n-1]) */
  private float m_fFnm1;
  /** f([n]) */
  private float m_fFn;
  /** f(x[n+1]) */
  private float m_fFnp1;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   * @param x0
   *        the first initial x-value
   * @param x1
   *        the second initial x-value
   */
  public SecantRootFinder (final AbstractFunction function, final float x0, final float x1)
  {
    super (function, MAX_ITERS);

    // Initialize x[n-1], x[n], f(x[n-1]), and f(x[n]).
    m_fXnm1 = x0;
    m_fFnm1 = function.at (m_fXnm1);
    m_fXn = x1;
    m_fFn = function.at (m_fXn);
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Return the current value of x[n-1].
   *
   * @return the value
   */
  public float getXnm1 ()
  {
    return m_fXnm1;
  }

  /**
   * Return the current value of x[n].
   *
   * @return the value
   */
  public float getXn ()
  {
    return m_fXn;
  }

  /**
   * Return the current value of x[n+1].
   *
   * @return the value
   */
  public float getXnp1 ()
  {
    return m_fXnp1;
  }

  /**
   * Return the current value of f(x[n-1]).
   *
   * @return the value
   */
  public float getFnm1 ()
  {
    return m_fFnm1;
  }

  /**
   * Return the current value of f(x[n]).
   *
   * @return the value
   */
  public float getFn ()
  {
    return m_fFn;
  }

  /**
   * Return the current value of f(x[n+1]).
   *
   * @return the value
   */
  public float getFnp1 ()
  {
    return m_fFnp1;
  }

  // -----------------------------//
  // RootFinder method overrides //
  // -----------------------------//

  /**
   * Do the secant iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {
    if (n == 1)
      return; // already initialized

    // Use the latest two points.
    m_fXnm1 = m_fXn; // x[n-1] = x[n]
    m_fXn = m_fXnp1; // x[n] = x[n+1]
    m_fFnm1 = m_fFn; // f(x[n-1]) = f(x[n])
    m_fFn = m_fFnp1; // f(x[n]) = f(x[n+1])
  }

  /**
   * Compute the next position of x[n+1].
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fPrevXnp1 = m_fXnp1;
    m_fXnp1 = m_fXn - m_fFn * (m_fXnm1 - m_fXn) / (m_fFnm1 - m_fFn);
    m_fFnp1 = m_aFunction.at (m_fXnp1);
  }

  /**
   * Check the position of x[n+1].
   *
   * @throws PositionUnchangedException
   */
  @Override
  protected void checkPosition () throws AbstractRootFinder.PositionUnchangedException
  {
    if (EqualsHelper.equals (m_fXnp1, m_fPrevXnp1))
    {
      throw new AbstractRootFinder.PositionUnchangedException ();
    }
  }

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  @Override
  protected boolean hasConverged ()
  {
    return Math.abs (m_fFnp1) < TOLERANCE;
  }
}