using _04_1_Gauss;
using System;

namespace _06_Newton_uklady_rownan
{

  public delegate double FW(double[] x);

  public class Newton_Raphson
  {
    public int licznik;
    private int n;

    public double[] Oblicz(double eps, double[] x0, FW[] fn, FW[,] fprim)
    {
      n = x0.Length;
      licznik = 0;
      double[] h;
      double[] x = (double[])x0.Clone();
      do
      {
        licznik++;
        double[] B = liczB(fn, x);
        double[,] J = liczJ(fprim, x);
        h = liczH(J, B);
        Dodaj(x, h);
      } while (Norma(h) > eps);
      return x;
    }

    private void Dodaj(double[] x, double[] h)
    {
      for (int i = 0; i < n; i++)
        x[i] = x[i] + h[i];
    }

    private double[] liczH(double[,] J, double[] B)
    {
      Gauss gauss = new Gauss();
      gauss.A = J;
      gauss.b = B;
      gauss.Wybor = MetodaWyboru.Czesciowy;
      double[] h = gauss.Oblicz();
      return h;
    }

    private double[,] liczJ(FW[,] fprim, double[] x)
    {
      double[,] J = new double[n, n];
      for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
          J[i, j] = fprim[i, j](x);
      return J;
    }

    private double[] liczB(FW[] fn, double[] x)
    {
      double[] B = new double[n];
      for (int i = 0; i < n; i++)
        B[i] = -fn[i](x);
      return B;
    }

    private double Norma(double[] h)
    {
      double norma = 0;
      for (int i = 0; i < n; i++)
        norma = norma + h[i] * h[i];
      norma = Math.Sqrt(norma);
      return norma;
    }
  }
}
