⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 direcmin.c

📁 统计模式识别算法包
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************/
/*                                                                            */
/*  direcmin - Minimize along a direction                                     */
/*                                                                            */
/*  Normally this returns the mean square error, which will be 0-1.           */
/*  If the user interrupted, it returns the negative mean square error.       */
/*                                                                            */
/*  This is a two step process.  First we find three points whose center has  */
/*  the smallest function value (we bound the minimum).                       */
/*  Then we use Brent's algorithm to refine the interval.                     */
/*                                                                            */
/*  We leave 'coefs' set at the point that produced the minimum and return    */
/*  the error function at that point.  We change the direction 'dir' to       */
/*  be the actual distance moved.                                             */
/*                                                                            */
/* Copyright (c) 1993 by Academic Press, Inc.                                 */
/*                                                                            */
/* All rights reserved.  Permission is hereby granted, until further notice,  */
/* to make copies of this diskette, which are not for resale, provided these  */
/* copies are made from this master diskette only, and provided that the      */
/* following copyright notice appears on the diskette label:                  */
/* (c) 1993 by Academic Press, Inc.                                           */
/*                                                                            */
/* Except as previously stated, no part of the computer program embodied in   */
/* this diskette may be reproduced or transmitted in any form or by any means,*/
/* electronic or mechanical, including input into storage in any information  */
/* system for resale, without permission in writing from the publisher.       */
/*                                                                            */
/* Produced in the United States of America.                                  */
/*                                                                            */
/* ISBN 0-12-479041-0                                                         */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include "const.h"       // System and limitation constants, typedefs, structs
#include "classes.h"     // Includes all class headers
#include "funcdefs.h"    // Function prototypes

double LayerNet::direcmin (
   TrainingSet *tptr , // Training set to use
   double start_err ,  // Error (function value) at starting coefficients
   int itmax ,         // Upper limit on number of iterations allowed
   double eps ,        // Small, but greater than machine precision
   double tol ,        // Brent's tolerance (>= sqrt machine precision)
   double *base ,      // Work area (stepping out point)
   double *direc )     // Work area (stepping out direction)
{
   int key, user_quit, iter ;
   double step, x1, x2, x3, t1, t2, numer, denom, max_step ;
   double xlow, xhigh, xbest, testdist ;
   double current_err, err, previous_err, step_err ;
   double prevdist, etemp, frecent, fthirdbest, fsecbest, fbest ;
   double tol1, tol2, xrecent, xthirdbest, xsecbest, xmid;
   double  first_step = 2.5 ; // Heuristically found best

   user_quit = 0 ;

/*
   Take one step out in the gradient direction.  First preserve
   original weights for use as departure point parameterized by STEP.
*/

   preserve ( base ) ;   // Establishes a base for stepping out
   step_out ( first_step , direc , base ) ;
   err = trial_error ( tptr ) ;

/*
   If it increased, we had numerical problems computing the direction or
   the direction itself is too large a step.
   Negate the direction and use -1, 0 and 1.618 as first three steps.
   Otherwise use 0, 1 and 2.618 as first three steps.
*/

   if (err > start_err) {
      negate_dir ( direc ) ;
      x1 = -first_step ;
      x2 = 0. ;
      previous_err = err ;
      current_err = start_err ;
      }
   else {
      x1 = 0. ;
      x2 = first_step ;
      previous_err = start_err ;
      current_err = err ;
      }

/*
   At this point we have taken a single step and the function decreased.
   Take one more step in the golden ratio.
   Also keep errors lined up as 'previous_err', 'current_err' and 'err'.
   The corresponding abscissae will be x1, x2 and x3.
*/

/************************************************************************   if (kbhit()) {          // Was a key pressed?
      key = getch () ;     // Read it if so
      while (kbhit())      // Flush key buffer in case function key
         getch () ;        // or key was held down
      if (key == 27)       // ESCape
         return (- err) ;
      }
***********************************************************************/
   x3 = x2 + 1.618034 * first_step ;
   step_out ( x3 , direc , base ) ;
   err = trial_error ( tptr ) ;

/*
   We now have three points x1, x2 and x3 with corresponding errors
   of 'previous_err', 'current_err' and 'err'.
   Endlessly loop until we bracket the minimum with the outer two.
*/

   while (err < current_err) {   // As long as we are descending...

/*********************************************************************      if (kbhit()) {          // Was a key pressed?
         key = getch () ;     // Read it if so
         while (kbhit())      // Flush key buffer in case function key
            getch () ;        // or key was held down
         if (key == 27) {     // ESCape
            user_quit = 1 ;
            break ;
            }
         }

********************************************************************//*
   Try a parabolic fit to estimate the location of the minimum.
*/

      t1 = (x2 - x1) * (current_err - err) ;
      t2 = (x2 - x3) * (current_err - previous_err) ;
      denom = 2. * ( t2 - t1 ) ;
      if (fabs ( denom ) < eps) {
         if (denom > 0.)
            denom = eps ;
         else
            denom = -eps ;
         }
      step = x2 + ((x2 - x1) * t1  -  (x2 - x3) * t2) / denom ;//Here if perfect
      max_step = x2 + 200. * (x3 - x2) ; // Don't jump too far

      if ((x2 - step) * (step - x3)  >  0.) {         // It's between x2 and x3
         step_out ( step , direc , base ) ;
         step_err = trial_error ( tptr ) ;

         if (step_err < err) {   // It worked!  We found min between b and c.

            x1 = x2 ;
            x2 = step ;
            previous_err = current_err ;
            current_err = step_err ;
            goto BOUNDED ;
            }
         else if (step_err > current_err) { // Slight miscalc.  Min at x2.
            x3 = step ;
            err = step_err ;
            goto BOUNDED ;
            }
         else {             // Parabolic fit was total waste.  Use default.
            step = x3 + 1.618034 * (x3 - x2) ;
            step_out ( step , direc , base ) ;
            step_err = trial_error ( tptr ) ;
            }
         }

      else if ((x3 - step) * (step - max_step) > 0.0) { // Between x3 and lim
         step_out ( step , direc , base ) ;
         step_err = trial_error ( tptr ) ;
         if (step_err < err) {  // Decreased, so advance by golden ratio
            x2 = x3 ;
            x3 = step ;
            step = x3 + 1.618034 * (x3 - x2) ;
            current_err = err ;
            err = step_err ;
            step_out ( step , direc , base ) ;
            step_err = trial_error ( tptr ) ;
            }
         }

      else if ((step - max_step) * (max_step - x3)  >= 0.) {  // Beyond limit
         step = max_step ;
         step_out ( step , direc , base ) ;
         step_err = trial_error ( tptr ) ;
         if (step_err < err) {  // Decreased, so advance by golden ratio
            x2 = x3 ;
            x3 = step ;
            step = x3 + 1.618034 * (x3 - x2) ;
            current_err = err ;
            err = step_err ;
            step_out ( step , direc , base ) ;
            step_err = trial_error ( tptr ) ;
            }
         }

      else {  // Wild!  Reject parabolic and use golden ratio.
         step = x3 + 1.618034 * (x3 - x2) ;
         step_out ( step , direc , base ) ;
         step_err = trial_error ( tptr ) ;
         }

/*
   Shift three points and continue endless loop
*/

      x1 = x2 ;
      x2 = x3 ;
      x3 = step ;
      previous_err = current_err ;
      current_err = err ;
      err = step_err ;
      } // Endless stepping out loop

BOUNDED:
   step_out ( x2 , direc , base);//Leave coefs at min

   if (x1 > x3) {  // We may have switched direction at start.
      t1 = x1 ;    // Brent's method which follows assumes ordered parameter.
      x1 = x3 ;
      x3 = t1 ;
      }

   if (user_quit) {
      update_dir ( x2 , direc ) ;// Make it be the actual dist moved
      return -current_err ;
      }

/*
--------------------------------------------------------------------------------

   At this point we have bounded the minimum between x1 and x3.

   Go to the refinement stage.  We use Brent's algorithm.

--------------------------------------------------------------------------------
*/

/*
  Initialize prevdist, the distance moved on the previous step, to 0 so that
  the 'if (fabs ( prevdist )  >  tol1)' encountered on the first iteration
  below will fail, forcing a golden section the first time.  Also initialize
  step to 0 to avoid a zealous compiler from pointing out that it was
  referenced before being set.
*/

   prevdist = step = 0.0 ;

/*
   We always keep the minimum bracketed between xlow and xhigh.
   xbest has the min function so far (or latest if tie).
   xsecbest and xthirdbest are the second and third best.
*/

   xbest = xsecbest = xthirdbest = x2 ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -