Blame multifit/lmmisc.c

Packit 67cb25
/* multifit/lmmisc.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2014 Patrick Alken
Packit 67cb25
 * 
Packit 67cb25
 * This program is free software; you can redistribute it and/or modify
Packit 67cb25
 * it under the terms of the GNU General Public License as published by
Packit 67cb25
 * the Free Software Foundation; either version 3 of the License, or (at
Packit 67cb25
 * your option) any later version.
Packit 67cb25
 * 
Packit 67cb25
 * This program is distributed in the hope that it will be useful, but
Packit 67cb25
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 67cb25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 67cb25
 * General Public License for more details.
Packit 67cb25
 * 
Packit 67cb25
 * You should have received a copy of the GNU General Public License
Packit 67cb25
 * along with this program; if not, write to the Free Software
Packit 67cb25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
/* compute step dx by solving (J^T J + mu*I) dx = -J^T f */
Packit 67cb25
static int
Packit 67cb25
lmniel_calc_dx(const double mu, const gsl_matrix *A, const gsl_vector *rhs,
Packit 67cb25
               gsl_vector *dx, lmniel_state_t *state)
Packit 67cb25
{
Packit 67cb25
  int status;
Packit 67cb25
  gsl_matrix *A_copy = state->A_copy;
Packit 67cb25
  gsl_vector_view diag = gsl_matrix_diagonal(A_copy);
Packit 67cb25
Packit 67cb25
  /* make a copy of J^T J matrix */
Packit 67cb25
  gsl_matrix_memcpy(A_copy, A);
Packit 67cb25
Packit 67cb25
  /* augment normal equations with LM parameter: A -> A + mu*I */
Packit 67cb25
  gsl_vector_add_constant(&diag.vector, mu);
Packit 67cb25
Packit 67cb25
  status = gsl_linalg_QR_decomp(A_copy, state->work);
Packit 67cb25
  if (status)
Packit 67cb25
    return status;
Packit 67cb25
Packit 67cb25
  status = gsl_linalg_QR_solve(A_copy, state->work, rhs, dx);
Packit 67cb25
  if (status)
Packit 67cb25
    return status;
Packit 67cb25
Packit 67cb25
  return GSL_SUCCESS;
Packit 67cb25
} /* lmniel_calc_dx() */
Packit 67cb25
Packit 67cb25
/* compute x_trial = x + dx */
Packit 67cb25
static void
Packit 67cb25
lmniel_trial_step(const gsl_vector * x, const gsl_vector * dx,
Packit 67cb25
                  gsl_vector * x_trial)
Packit 67cb25
{
Packit 67cb25
  size_t i, N = x->size;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < N; i++)
Packit 67cb25
    {
Packit 67cb25
      double dxi = gsl_vector_get (dx, i);
Packit 67cb25
      double xi = gsl_vector_get (x, i);
Packit 67cb25
      gsl_vector_set (x_trial, i, xi + dxi);
Packit 67cb25
    }
Packit 67cb25
} /* lmniel_trial_step() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
lmniel_calc_dF()
Packit 67cb25
  Compute dF = F(x) - F(x + dx) = 1/2 (f - f_new)^T (f + f_new)
Packit 67cb25
*/
Packit 67cb25
static double
Packit 67cb25
lmniel_calc_dF(const gsl_vector *f, const gsl_vector *f_new)
Packit 67cb25
{
Packit 67cb25
  const size_t N = f->size;
Packit 67cb25
  size_t i;
Packit 67cb25
  double dF = 0.0;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < N; ++i)
Packit 67cb25
    {
Packit 67cb25
      double fi = gsl_vector_get(f, i);
Packit 67cb25
      double fnewi = gsl_vector_get(f_new, i);
Packit 67cb25
Packit 67cb25
      dF += (fi - fnewi) * (fi + fnewi);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  dF *= 0.5;
Packit 67cb25
Packit 67cb25
  return dF;
Packit 67cb25
} /* lmniel_calc_dF() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
lmniel_calc_dL()
Packit 67cb25
  Compute dL = L(0) - L(dx) = 1/2 dx^T (mu * D^T D dx - g)
Packit 67cb25
Here, the mg input is -g
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static double
Packit 67cb25
lmniel_calc_dL(const double mu, const gsl_vector *diag,
Packit 67cb25
               const gsl_vector *dx, const gsl_vector *mg)
Packit 67cb25
{
Packit 67cb25
  const size_t p = dx->size;
Packit 67cb25
  size_t i;
Packit 67cb25
  double dL = 0.0;
Packit 67cb25
Packit 67cb25
  for (i = 0; i < p; ++i)
Packit 67cb25
    {
Packit 67cb25
      double dxi = gsl_vector_get(dx, i);
Packit 67cb25
      double di = gsl_vector_get(diag, i);
Packit 67cb25
      double mgi = gsl_vector_get(mg, i); /* -g_i */
Packit 67cb25
Packit 67cb25
      dL += dxi * (mu * di * di * dxi + mgi);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  dL *= 0.5;
Packit 67cb25
Packit 67cb25
  return dL;
Packit 67cb25
} /* lmniel_calc_dL() */