サブ fit.js   Last modified: Mar 25, 2004
// S-JIS コードでなくてはならない

var n, ip, loop
var resid, cterm, d, x, y, ff, p, p0, p1, delta, x_value, fj
var MAXIT = 500
var EPSILON = 1e-7

function residual()
{
  var i, temp
  resid = 0.0
  for (i = 0; i < n; i++) {
    x_value = x[i]
    temp = y[i]-Function(0, i)
    resid += temp*temp
  }
}

function solinv_fit()
{
  var i, j, k, l, nold
  var f, g, h, s, sl, sum, temp

  for (i = 0; i < ip; i++) {
    p[i] = p0[i]
  }
  residual()
  for (i = 0; i < n; i++) {
    x_value = x[i]
    f = Function(1, i)
    fj[i][ip] = y[i]-f
  }
  for (j = 0; j < ip; j++) {
    temp = 0
    for (i = 0; i < n; i++) {
      temp += fj[i][j]*fj[i][ip]
    }
    ff[j] = temp
  }
  nold = n
  n += ip
  for (j = 0; j < ip; j++) {
    for (i = 0; i < ip; i++) {
      fj[nold+j][i] = (j == i) ? Math.sqrt(cterm) : 0
    }
    fj[nold+j][ip] = 0
  }
  sl = 1e-30
  for (j = 0; j <= ip; j++) {
    h = 0
    for (k = j; k < n; k++) {
      d[k] = fj[k][j]
      h += d[k]*d[k]
    }
    if (h < sl) {
      g = 0
    }
    else {
      g = Math.sqrt(h)
      f = fj[j][j]
      if (f >= 0) {
        g = -g
      }
      d[j] = f-g
      h -= f*g
      for (k = j+1; k <= ip; k++) {
        s = 0
        for (l = j; l < n; l++) {
          s += d[l]*fj[l][k]
        }
        s /= h
        for (l = j; l < n; l++) {
          fj[l][k] -= d[l]*s
        }
      }
    }
    fj[j][j] = g
  }
  n = nold
  for (i = ip-1; i >= 0; i--) {
    sum = fj[i][ip]
    for (j = i+1; j < ip; j++) {
      sum -= delta[j]*fj[i][j]
    }
    delta[i] = (fj[i][i] == 0) ? 0 : sum/fj[i][i]
  }
}

function output(title, method)
{
  var yval, i
  var p_name
  p_name = new Array("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
  printf("%s  %s 法\n\n", title, method == 1 ? "Marquardt" : "Simplex")
  for (i = 0; i < ip; i++) {
    printf("%s ・・・・・・・・・・・・・%22.14g\n", p_name[i], p[i])
  }
  printf("残差平方和 ・・・・%22.14g\n\n", resid)
  printf("★ 予測値および残差\n\nケース       独立変数       従属変数        予測値          残差\n")
  for (i = 0; i < n; i++) {
    x_value = x[i]
    yval = Function(0, i)
    printf("%6i%15.7g%15.7g%15.7g%15.7g\n",i+1, x_value, y[i], yval, y[i]-yval)
  }
}

function marquardt(ip0, inival, title)
{
  var errset = 0, i, diverg = 0, flag = 0
  var check, check0, rchange, res0, res1

  ip = ip0
  fj = makeMatrix(n+ip, ip)
  ff = makeVector(ip)
  p = makeVector(ip)
  p0 = makeVector(ip)
  p1 = makeVector(ip)
  delta = makeVector(ip)
  for (i = 0; i < ip; i++) {
    p0[i] = inival[i]
  }
  d = makeVector(n)
  document.Result.result.value = "非線形最小二乗法によるあてはめ収束状況"+newline

  cterm = 100
  for (loop = 1; loop <= MAXIT; loop++) {
    solinv_fit()
    res0 = resid
    flag = 0
    for (i = 0; i < ip; i++) {
      p1[i] = p0[i]+delta[i]
      if (Math.abs(delta[i]/p1[i]) > EPSILON) {
        flag = 1
      }
    }
    check = 0
    for (i = 0; i < ip; i++) {
      check -= (ff[i]+cterm*delta[i])*delta[i]
    }
    check0 = check
    for (i = 0; i < ip; i++) {
      p[i] = p1[i]
    }
    residual()
    printf("residual = %g\n", resid)
    res1 = resid
    if (res1 == 0) {
      break
    }
    rchange = res1-res0
    if (rchange <= 0) {
      diverg = 0
      if (errset == 1) {
        errset = 0
      }
      check = rchange/check0
      if (-rchange/res1 < EPSILON && flag == 0) {
        break
      }
      if (check > 0.75) {
        cterm *= 0.5
      }
      else if (check < 0.25) {
        cterm *= 5
      }
      for (i = 0; i < ip; i++) {
        p0[i] = p1[i]
      }
    }
    else {
      diverg++
      errset = 1
      if (diverg > 10) {
        if (flag == 1) {
          printf("\n発散してしまいました。初期値が不適当です。\n")
          break
        }
        for (i = 0; i < ip; i++) {
          p0[i] = p1[i]
        }
      }
      else {
        cterm *= 5
        loop--
      }
    }
  }
  document.Result.result.value = "非線形最小二乗法によるあてはめ結果"+newline
  for (i = 0; i < ip; i++) {
    p[i] = p1[i]
  }
  if (loop > MAXIT || flag) {
    printf("\n収束しませんでした!初期値が不適当です。\n")
  }
  output(title, 1)
}

function simplex(ip0, inival, title)
{
  var i, j, l1, l2, l5, loop0, m, mi, mx,  fi9, fj9, pa, res, resid_old, s, s1, s2, z1, z2

  document.Result.result.value = "非線形最小二乗法によるあてはめ収束状況"+newline

  ip = ip0
  p0 = makeVector(ip)
  for (i = 0; i < ip; i++) {
    p0[i] = inival[i]
  }
  pa = makeMatrix(ip+3, ip+3)
  res = makeVector(ip+3)
  s = makeVector(ip)
  p = makeVector(ip)
  resid_old = 1e33
  delta = new Array(ip+1)
  for (i = 0; i < ip; i++) {
    delta[i] = p0[i]*(Math.random()*0.1-0.05)
  }
  l5 = ip+1
  l1 = l5+1
  l2 = l5+2
  fi9 = l5
  fj9 = ip
  s1 = 2/fj9
  s2 = 3/fj9
  z1 = (fi9+1)/fj9
  z2 = (2*fi9+1)/fj9
  for (i = 0; i < l5; i++) {
    for (j = 0; j < ip; j++) {
      pa[j][i] = p0[j]
    }
    if (i <= ip) {
      pa[i][i] = p0[i]+delta[i]
    }
    for (m = 0; m < ip; m++) {
      p[m] = pa[m][i]
    }
    residual()
    printf("residual = %g\n", resid)
    res[i] = resid
  }
  loop0 = 0
  for (loop = 1; loop <= MAXIT; loop++) {
    for (j = 0; j < ip; j++) {
      s[j] = 0
    }
    mx = mi = 0
    for (i = 0; i < l5; i++) {
      if (res[i] > res[mx]) {
        mx = i
      }
      if (res[i] < res[mi]) {
        mi = i
      }
      for (j = 0; j < ip; j++) {
        s[j] += pa[j][i]
      }
    }
    if (++loop0 > MAXIT) {
      break
    }
    if (res[mx] < EPSILON || res[mi] < EPSILON) {
      break
    }
    if ((res[mx]-res[mi])/res[mi] <= EPSILON) {
      break
    }
    loop0 = 0
    i = l1
    for (j = 0; j < ip; j++) {
      pa[j][l1] = s1*s[j]-z1*pa[j][mx]
    }
    for (m = 0; m < ip; m++) {
      p[m] = pa[m][l1]
    }
    residual()
    printf("residual = %g\n", resid)
    res[l1] = resid
    if (res[l1] < res[mi]) {
      for (j = 0; j < ip; j++) {
        pa[j][l2] = s2*s[j]-z2*pa[j][mx]
      }
      for (m = 0; m < ip; m++) {
        p[m] = pa[m][l2]
      }
      residual()
      printf("residual = %g\n", resid)
      res[l2] = resid
      if (res[l2] <= res[l1]) {
        i = l2
      }
    }
    else if (res[l1] > res[mx]) {
      for (j = 0; j < ip; j++) {
        pa[j][l2] = s[j]/fi9
      }
      for (m = 0; m < ip; m++) {
        p[m] = pa[m][l2]
      }
      residual()
      printf("residual = %g\n", resid)
      res[l2] = resid
      if (res[l2] >= res[mx]) {
        for (i = 0; i < l5; i++) {
          if (i != mi) {
            for (j = 0; j < ip; j++) {
              pa[j][i] = (pa[j][i]+pa[j][mi])*0.5
            }
            for (m = 0; m < ip; m++) {
              p[m] = pa[m][i]
            }
            residual()
            printf("residual = %g\n", resid)
            res[i] = resid
          }
        }
        continue
      }
      i = l2
    }
    for (j = 0; j < ip; j++) {
      pa[j][mx] = pa[j][i]
    }
    res[mx] = res[i]
  }
  document.Result.result.value = "非線形最小二乗法によるあてはめ結果"+newline
  if (loop0 > MAXIT || loop > MAXIT) {
    printf("収束しませんでした。\n")
  }
  for (j = 0; j < ip; j++) {
    p[j] = pa[j][mi]
  }
  resid = res[mi]
  output(title, 2)
}


・ 直前のページへ戻る  ・ E-mail to Shigenobu AOKI

Made with Macintosh