• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

ne_sup_sa.c

00001 /*===========================================================================
00002  NetEvo Foundation Library
00003  Copyright (C) 2009, 2010 Thomas E. Gorochowski <tgorochowski@me.com>
00004  Bristol Centre for Complexity Sciences, University of Bristol, Bristol, UK
00005  ---------------------------------------------------------------------------- 
00006  NetEvo is a computing framework designed to allow researchers to investigate 
00007  evolutionary aspects of dynamical complex networks. By providing tools to 
00008  easily integrate each of these factors in a coherent way, it is hoped a 
00009  greater understanding can be gained of key attributes and features displayed 
00010  by complex systems.
00011  
00012  NetEvo is open-source software released under the Open Source Initiative 
00013  (OSI) approved Non-Profit Open Software License ("Non-Profit OSL") 3.0. 
00014  Detailed information about this licence can be found in the COPYING file 
00015  included as part of the source distribution.
00016  
00017  This library is distributed in the hope that it will be useful, but
00018  WITHOUT ANY WARRANTY; without even the implied warranty of
00019  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020  ============================================================================*/
00021 
00022 
00023 #include "ne_sup_sa.h"
00024 #include "ne_evo.h"
00025 #include <time.h>
00026 #include <gsl/gsl_rng.h>
00027 #include <math.h>
00028 
00029 /* Shared random number generator */
00030 extern gsl_rng* neRng;
00031 
00032 
00033 ne_sup_sa_params_t * ne_sup_sa_params_alloc (int initialTrials, double tempReduce, int mainTrails,
00034                                     int acceptTrials, int acceptRunsNoChange, double minTemp,
00035                                     int maxIterations, double (*initialTempFn) (double),
00036                                     ne_per_t *QFn, ne_mut_t *mutationFn, ne_sim_fn_t *simFn,
00037                                     void *simParams, ne_dyn_vec_t *initCond, 
00038                                     ne_sup_sa_analysis_fn_t *analysisFn, FILE *evoFile)
00039 {
00040    ne_sup_sa_params_t *params;
00041    
00042    if ((params = (ne_sup_sa_params_t *)malloc(sizeof(ne_sup_sa_params_t))) == NULL) {
00043       ne_error("ne_sup_sa_alloc: Could not allocate memory for parameters.");
00044       return NULL;
00045    }
00046    
00047    params->initialTrials = initialTrials;
00048    params->tempReduce = tempReduce;
00049    params->mainTrials = mainTrails;
00050    params->acceptTrials = acceptTrials;
00051    params->acceptRunsNoChange = acceptRunsNoChange;
00052    params->minTemp = minTemp;
00053    params->maxIterations = maxIterations;
00054    params->initialTempFn = initialTempFn;
00055    params->QFn = QFn;
00056    params->mutationFn = mutationFn;
00057    params->simFn = simFn;
00058    params->simParams = simParams;
00059    params->initCond = initCond;
00060    params->analysisFn = analysisFn;
00061    params->evoFile = evoFile;
00062    
00063    return params;
00064 }
00065 
00066 
00067 void ne_sup_sa_params_free (ne_sup_sa_params_t *params)
00068 {
00069    free(params);
00070 }
00071 
00072 
00073 ne_sys_t * ne_sup_sa_run (ne_sys_t *sys, ne_sup_sa_params_t *params)
00074 {  
00075    int i, accepts, noChange, iteration;
00076    double T, dQmax;
00077    ne_sup_sa_trail_results_t *results = NULL;
00078    double QChosen;
00079    
00080    /* Initialise variables */
00081    iteration = 1;
00082    
00083    /* Create structure used to return the results of each trial */
00084    results = (ne_sup_sa_trail_results_t *)malloc(sizeof(ne_sup_sa_trail_results_t));
00085    results->curDyn = NULL;
00086    results->Q1 = -1;
00087    
00088    /* First trials at initial T of infinity (or very large in our case) */
00089    T = 10000000000000.0;
00090    dQmax = 0.0;
00091    
00092    if (params->analysisFn != NULL) {
00093       (params->analysisFn)(sys, NULL, iteration, T, -1, TRUE);
00094    }
00095    
00096    if (params->evoFile != NULL) {
00097       ne_evo_initial(sys, params->evoFile);
00098    }
00099    
00100    /* ===================== FIND INITIAL TEMPERATURE ===================== */
00101    
00102    /* Carry out a number of initial trails to estimate starting temperature */
00103    for ( i=0; i<params->initialTrials; i++ ) {
00104       
00105       /* Try a trail at infinite temperature */
00106       sys = ne_sup_sa_trail(sys, T, results, params);
00107       
00108       /* Check to see if accepted and output result */
00109       if ( results->a == 1 ) {
00110          if (params->analysisFn != NULL) {
00111             (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q2, FALSE);
00112          }
00113       }
00114       else {
00115          if (params->analysisFn != NULL) {
00116             (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q1, FALSE);
00117          }
00118       }
00119       
00120       /* Find the worse result for the performance measure to initialise inital temp */
00121       dQmax = fmax(results->dQ, dQmax);
00122       
00123       /* See if we have already found an optimum and stop if so */
00124       if ((results->a == 1 && results->Q2 == 0.0) ||
00125           (results->a == 0 && results->Q1 == 0.0)) {
00126          return sys;
00127       }
00128       
00129       iteration++;
00130    }
00131 
00132    /* Update tempertaure based on these trials */
00133    if (dQmax != 0.0) {
00134       T = (params->initialTempFn)(dQmax);
00135    }
00136    else {
00137       /* No difference could be found so pick initial temp based on performance measure */
00138       T = results->Q1 * 0.2;
00139    }
00140    
00141    /* ===================== SIMULATED ANNEALING PROCESS ===================== */
00142    
00143    /* Flag signifying the number of runs with no change */
00144    noChange = 0;
00145 
00146    /* Check that the temperature has not already been set to 0 */
00147    if ( T != 0.0 ) {
00148       
00149       /* Continue to lower temperature by tempReducePer% each run until no changes in acceptRunsNoChange runs */
00150       do {
00151          
00152          /* Run for mainTrials more trials or acceptTrials accepting trials */
00153          accepts = 0;
00154          for ( i=0; i<params->mainTrials; i++ ) {
00155          
00156             /* Check if we have reached the maximum number of iterations */
00157             if (iteration > params->maxIterations) {
00158                break;
00159             }           
00160             
00161             /* Run a trail */
00162             sys = ne_sup_sa_trail(sys, T, results, params);
00163             
00164             /* Check to see if accepted and output result */
00165             if ( results->a == 1 ){
00166                if (params->analysisFn != NULL) {
00167                   (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q2, FALSE);
00168                }
00169                QChosen = results->Q2;
00170             }
00171             else{
00172                QChosen = results->Q1;
00173                if (params->analysisFn != NULL) {
00174                   (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q1, FALSE);
00175                }
00176             }
00177             
00178             iteration++;
00179 
00180             /* Update accepting counters */
00181             if ( (int)results->a == 1 ){
00182                accepts++;
00183                if ( results->Q2 == 0.0 )
00184                   break;
00185             }
00186             else{
00187                if ( results->Q1 == 0.0 )
00188                   break;
00189             }
00190             if ( accepts >= params->acceptTrials ) 
00191                break;
00192          }
00193          
00194          /* Update the counter to check if no changes are made at lower temps */
00195          if ( accepts == 0 )
00196             noChange++;
00197          else
00198             noChange = 0;
00199          
00200          /* Reduce temperature */
00201          T = T*params->tempReduce;
00202          
00203       } while (noChange <= params->acceptRunsNoChange && 
00204                T > params->minTemp && 
00205                iteration <= params->maxIterations && 
00206                QChosen != 0.0);
00207    }
00208    
00209    
00210    /* Output the final results */
00211    if ( results->a == 1 ){
00212       if (params->analysisFn != NULL) {
00213          (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q2, TRUE);
00214       }
00215    }
00216    else{
00217       if (params->analysisFn != NULL) {
00218          (params->analysisFn)(sys, results->curDyn, iteration, T, results->Q1, TRUE);
00219       }
00220    }
00221    
00222    /* Free used memory */
00223    ne_dyn_vec_free(results->curDyn);
00224    free(results);
00225    
00226    /* Return the new ne_sys */
00227    return sys;
00228 }
00229 
00230 
00231 ne_sys_t * ne_sup_sa_trail (ne_sys_t *sys, double T, ne_sup_sa_trail_results_t *results, 
00232                  ne_sup_sa_params_t *params)
00233 {
00234    int a;
00235    double dQ;
00236    igraph_bool_t res;
00237    ne_dyn_vec_t *dynOut2 = NULL;
00238    ne_sys_t *S2 = NULL;
00239    char strBuffer[1024];
00240    
00241    strBuffer[0] = '\0';
00242    
00243    /* Set inital dQ value incase none is found */
00244    dQ = 0.0;
00245 
00246    /* Make a copy of the system */
00247    S2 = ne_sys_clone(sys);
00248 
00249    /* Call mutational function to generate new topology */
00250    (params->mutationFn->fn)(S2, params->mutationFn->params, strBuffer);
00251 
00252    /* Do not accept changes by default */
00253    a = 0;
00254    
00255    /* Find the Q1 */
00256    /* Depending on the type of performance measure simulation of dynamics may be required */
00257    switch (params->QFn->type) {
00258          
00259       case NE_PER_TOP:
00260          if ( results->Q1 == -1 ) {
00261             results->Q1 = (params->QFn->fn)(sys, NULL, params->QFn->params);
00262          }
00263          else {
00264             if (results->a == 1) {
00265                results->Q1 = results->Q2;
00266             }
00267          }
00268          break;
00269          
00270       case NE_PER_DYN:
00271       case NE_PER_TOP_AND_DYN:
00272          if ( results->Q1 == -1 ) {
00273             results->Q1 = ne_sup_sa_simulate(sys, params);
00274          }
00275          else{
00276             if ( results->a == 1 ) {
00277                results->Q1 = results->Q2;
00278             }
00279          }
00280          break;
00281          
00282       default:
00283          results->Q1 = -1;
00284          break;
00285    }
00286    
00287    /* Check that connected and if not reject trial */
00288    igraph_is_connected(S2->graph, &res, IGRAPH_WEAK);
00289    if (res == TRUE) {
00290       
00291       /* Depending on the type of performance measure simulation of dynamics may be required */
00292       switch (params->QFn->type) {
00293             
00294          case NE_PER_TOP:
00295             results->Q2 = (params->QFn->fn)(S2, NULL, params->QFn->params);
00296             dQ = results->Q2 - results->Q1;
00297             break;
00298             
00299          case NE_PER_DYN:
00300          case NE_PER_TOP_AND_DYN:
00301             results->Q2 = ne_sup_sa_simulate(S2, params);
00302             dQ = results->Q2 - results->Q1;     
00303             break;
00304             
00305          default:
00306             dQ = 0;
00307             break;
00308       }
00309       
00310       if (dQ < 0.0) {
00311          
00312          /* Accept change */
00313          a = 1;
00314       }
00315       else {
00316          
00317          /* Check for divide by zero */
00318          if (T != 0.0 && T > 0.0) {
00319             
00320             /* Calculate probability of still accepting */
00321             /* There are several possible accepting forms we use standard */
00322             if (gsl_rng_uniform(neRng) <= exp(-dQ/T)) {
00323                /* Make change even though worse cost */
00324                a = 1;
00325             }
00326          }
00327       }
00328    }
00329 
00330    /* Set results to be used by caller */
00331    results->dQ = dQ;
00332    results->a = a;
00333    
00334    /* Make updates based on outcome of change */
00335    if ( a == 1 ) {
00336 
00337       /* Update the current dynamics to the new data */
00338       ne_dyn_vec_free(results->curDyn);
00339       results->curDyn = dynOut2;
00340       
00341       /* Output the evolutionary steps */
00342       if (params->evoFile != NULL){
00343          fprintf(params->evoFile, "%s%s", strBuffer, ne_evo_step(NE_STEP_EVO));
00344          fflush(params->evoFile);
00345       }
00346       
00347       /* Update the master network as change was accepted */
00348       ne_sys_free(sys);
00349       return S2;
00350    }
00351    else{
00352       
00353       /* Free memory used for altered dynamics */
00354       ne_dyn_vec_free(dynOut2);
00355       
00356       /* Change was not successful */
00357       ne_sys_free(S2);
00358       return sys;
00359    }
00360 }
00361 
00362 
00363 double ne_sup_sa_simulate (ne_sys_t *sys, ne_sup_sa_params_t *params) {
00364    
00365    int i;
00366    ne_dyn_vec_t **dynOuts;
00367    double *perfVals;
00368    double perfSum = 0;
00369    
00370 //#ifdef BENCHMARK
00371    clock_t ctime_1, ctime_2;
00372    ctime_1 = clock();
00373 //#endif
00374    
00375    perfSum = 0;
00376    dynOuts = (ne_dyn_vec_t **)malloc(sizeof(ne_dyn_vec_t *)*params->initCond->curSize);
00377    perfVals = (double *)malloc(sizeof(double)*params->initCond->curSize);
00378    
00379    /* Run each simulation using OpenMP */
00380    #pragma omp parallel for
00381    for ( i=0; i<params->initCond->curSize; i++ ) {
00382       
00383       /* Simulate the system */
00384       dynOuts[i] = (params->simFn)(sys, params->simParams, params->initCond->data[i], NULL);
00385       
00386       /* Calculate the performance measure */
00387       perfVals[i] += (params->QFn->fn)(sys, dynOuts[i], params->QFn->params);
00388       
00389       /* Free simulation memory */
00390       ne_dyn_vec_free(dynOuts[i]);
00391    }
00392    
00393    for (i=0; i<params->initCond->curSize; i++ ) {
00394       perfSum += perfVals[i];
00395    }
00396    
00397    free(dynOuts);
00398    free(perfVals);
00399    
00400 //#ifdef BENCHMARK
00401    ctime_2 = clock();
00402    ne_log("BENCHMARK: ne_sup_sa_simulate - CPU time to simulate dynamics: %f seconds\n", 
00403          (double)(ctime_2 - ctime_1) / (double)CLOCKS_PER_SEC);
00404 //#endif
00405    
00406    /* Return the average performance measure */
00407    return perfSum / params->initCond->curSize;
00408 }
00409 
00410 
00411 double ne_sup_sa_int_temp_basic (double qMax) 
00412 {
00413    return 4*qMax;
00414 }
00415 

Generated on Thu Aug 26 2010 11:04:24 for NetEvo by  doxygen 1.7.1