/* Copyright (C) 1999-2000 Simon N. Wood snw@st-and.ac.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. (www.gnu.org/copyleft/gpl.html) You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/ /*****************************************************************************/ /* This is source code for stochastic minimisation routines, and direct */ /* search minimisers. */ /*****************************************************************************/ #include #include #include #include "rangen.h" void ErrorMessage(char *msg,int fatal); double fastcrawl(double func(double*),int m,int *nk,double *p0,double *dp,double *p,int geo,int finalcall) /* This routine is a faster grid crawling minimiser. The idea is that the routine works through nodes of an m-dimensional grid, at each step it picks any of the 2m nearest nodes not previously tried at random - if this node has a lower function value then it is accepted as the current node and the proccess repeats. Termination occurs when the current node is lower than all 2m nearest neighbours. On well behaved functions this routine is much faster than a global search of the grid, but of course it can stall in narrow valleys, as a result of the coarseness of the grid. There are two versions implemented: 1. When compact=0 then the routine sets up an array which stores every node on the grid. This is used to ensure that no node is visited twice, but also means that the size of the grid is limited. 2. When compact=1 the routine only ensures that the neighbours of the current node are not revisted before a new node is chosen or termination occurs. Once a new node is accepted, the routine treats all nodes except the one just moved from as valid nodes to try. Hence nodes can be revisited in theory. func() the function to be minimised - often this will be a dummy function that calls the function that is actually to be minimised, in order that extra arguments can be supplied to the real function. m - number of dimensions nk[i] - number of gridpoints for the ith dimension p0[i] - lowest value of ith parameter dp[i] - step size for ith parameter p[i] - minimising parameters returned at exit geo - if this is 1 then parameters are stepped geometrically i.e. p[i]=p0[i]*pow(dp[i],j), otherwise p[i]=p0[i]+j*dp[i]. finalcall - set to 1 to get a final call at optimum parameters */ { int i,j,k,*pos,possible,*grid,*move,*moveok,compact=1; unsigned long n0,n=1,z; double *pt,f0,f1; pos=(int *)calloc((size_t) m,sizeof(int)); // current grid position for (i=0;i=0;i--) z=z*nk[i]+pos[i]; // pos -> array location if ((pos[j]=0 && moveok[2*j+1]) { move[possible]=-j-1;possible++;} else moveok[2*j+1]=0; } else { z=pos[m-1];for (i=m-2;i>=0;i--) z=z*nk[i]+pos[i]; // pos -> array location if ((pos[j]>=0)&&!grid[z]) { move[possible]=-j-1;possible++;} } pos[j]++; } if (!possible) { free(pos);free(move);free(pt);if (compact) free(moveok); else free(grid); if (finalcall) f1=func(p); return(f0); // minimum (at least locally) } else { k=ranint(0,possible-1); // choose a random (but unvisited) neighbour pos[abs(move[k])-1]+=move[k]/abs(move[k]); if (geo) for (i=0;i=0;i--) z=z*nk[i]+pos[i]; // pos -> array location grid[z]=1; // marking node as visited } if (f10)||(pos[i]==0&&inc[i]<0)) { inc[i]=-inc[i];} else {pos[i]+=inc[i];break;} } } // tidy up .... free(pos);free(inc);free(max);free(pt); if (finalcall) f1=func(p); return(f0); }