Changeset 899


Ignore:
Timestamp:
Feb 22, 2008 2:08:40 PM (15 years ago)
Author:
mmc
Message:

Added a -fitness option to the "perform" operation. Right now, you can
specify just the name of an output quantity, and that quantity can be
minimized or maximized. In the future, there should be an expression
parser so you can enter any function of Rappture quantities.

Fixed up the example so that it runs the Rosenbrock function, which is
difficult to minimize. Added a visualize.tcl script, so you can visualize
the output from many different runXXXX.xml files.

Location:
trunk/optimizer
Files:
2 added
1 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/optimizer/examples/simple.tcl

    r898 r899  
    4848Rappture::optimizer optim -tool $tool -using pgapack
    4949
    50 optim add number input.number(temperature) -min 200 -max 400
    51 optim add number input.number(Ef) -min 0 -max 1.1
    52 optim configure -popsize 500 -maxruns 5
     50optim add number input.number(x1) -min -2 -max 2
     51optim add number input.number(x2) -min -2 -max 2
     52optim configure -operation minimize -popsize 100 -maxruns 200
    5353
    54 set status [optim perform -updatecommand {puts "checking"}]
     54set status [optim perform \
     55    -fitness output.number(f).current \
     56    -updatecommand {puts "checking"}]
    5557
    5658puts "done: $status"
  • trunk/optimizer/examples/tool.xml

    r898 r899  
    22<run>
    33    <tool>
    4         <about>Press Simulate to view results.</about>
    5         <command>tclsh @tool/fermi.tcl @driver</command>
     4        <about>This tool is a good example for optimization.  It implements the Rosenbrock function:
     5
     6f(x1,x2) = 100(x2 - x1**2)**2 + (1-x1)**2
     7
     8This has a minimum at (x1,x2) = (1,1).
     9
     10Press Simulate to view results.</about>
     11        <command>tclsh @tool/rosenbrock.tcl @driver</command>
    612    </tool>
    713    <input>
    8         <number id="temperature">
     14        <number id="x1">
    915            <about>
    10                 <label>Ambient temperature</label>
    11                 <description>Temperature of the environment.</description>
     16                <label>X1</label>
     17                <description>first coordinate</description>
    1218            </about>
    13             <units>K</units>
    14             <min>0K</min>
    15             <max>500K</max>
    16             <default>300K</default>
    17             <preset>
    18                 <value>300K</value>
    19                 <label>300K (room temperature)</label>
    20             </preset>
    21             <preset>
    22                 <value>77K</value>
    23                 <label>77K (liquid nitrogen)</label>
    24             </preset>
    25             <preset>
    26                 <value>4.2K</value>
    27                 <label>4.2K (liquid helium)</label>
    28             </preset>
     19            <min>-2</min>
     20            <max>2</max>
     21            <default>0</default>
    2922        </number>
    30         <number id="Ef">
     23        <number id="x2">
    3124            <about>
    32                 <label>Fermi Level</label>
    33                 <description>Energy at center of distribution.</description>
     25                <label>X2</label>
     26                <description>second coordinate</description>
    3427            </about>
    35             <units>eV</units>
    36             <min>-10eV</min>
    37             <max>10eV</max>
    38             <default>0eV</default>
     28            <min>-2</min>
     29            <max>2</max>
     30            <default>0</default>
    3931        </number>
    4032    </input>
    4133</run>
    42 
  • trunk/optimizer/src/plugin_pgapack.c

    r898 r899  
    1515 */
    1616#include "pgapack.h"
    17 #include "rp_optimizer_plugin.h"
     17#include "rp_optimizer.h"
    1818
    1919typedef struct PgapackData {
     
    9292 */
    9393RpOptimStatus
    94 PgapackRun(envPtr, evalProc)
     94PgapackRun(envPtr, evalProc, fitnessExpr)
    9595    RpOptimEnv *envPtr;           /* optimization environment */
    9696    RpOptimEvaluator *evalProc;   /* call this proc to run tool */
     97    char *fitnessExpr;            /* fitness function in string form */
    9798{
    9899    PgapackData *dataPtr =(PgapackData*)envPtr->pluginData;
     
    109110    PGASetPopSize(ctx, dataPtr->popSize);
    110111    PGASetPopReplaceType(ctx, dataPtr->popRepl);
     112    PGASetCrossoverType(ctx, PGA_CROSSOVER_UNIFORM);
    111113
    112114    PGASetUserFunction(ctx, PGA_USERFUNCTION_CREATESTRING, PgapCreateString);
     
    118120    PGASetUserFunction(ctx, PGA_USERFUNCTION_BUILDDATATYPE, PgapBuildDT);
    119121
    120     envPtr->evalProc = evalProc;  /* call this later for evaluations */
     122    envPtr->evalProc = evalProc;   /* plug these in for later during eval */
     123    envPtr->fitnessExpr = fitnessExpr;
    121124
    122125    /*
  • trunk/optimizer/src/rp_optimizer.c

    r898 r899  
    3333 */
    3434RpOptimEnv*
    35 RpOptimCreate(pluginData, cleanupProc)
    36     ClientData pluginData;        /* special data created for this env */
    37     RpOptimCleanup *cleanupProc;  /* routine to clean up pluginData */
     35RpOptimCreate(pluginDefn)
     36    RpOptimPlugin *pluginDefn;    /* plug-in handling this optimization */
    3837{
    3938    RpOptimEnv *envPtr;
    4039    envPtr = (RpOptimEnv*)malloc(sizeof(RpOptimEnv));
    41     envPtr->pluginData  = pluginData;
    42     envPtr->cleanupProc = cleanupProc;
    43     envPtr->toolData    = NULL;
     40
     41    envPtr->pluginDefn = pluginDefn;
     42    envPtr->pluginData = NULL;
     43    envPtr->toolData   = NULL;
     44
     45    if (pluginDefn->initProc) {
     46        envPtr->pluginData = (*pluginDefn->initProc)();
     47    }
    4448
    4549    envPtr->numParams = 0;
     
    211215    int n;
    212216
     217    if (envPtr->pluginDefn && envPtr->pluginDefn->cleanupProc) {
     218        (*envPtr->pluginDefn->cleanupProc)(envPtr->pluginData);
     219    }
    213220    for (n=0; n < envPtr->numParams; n++) {
    214221        RpOptimCleanupParam(envPtr->paramList[n]);
    215     }
    216     if (envPtr->cleanupProc) {
    217         (*envPtr->cleanupProc)(envPtr->pluginData);
    218222    }
    219223    free(envPtr->paramList);
  • trunk/optimizer/src/rp_optimizer.h

    r898 r899  
    2323#include <string.h>
    2424#include <malloc.h>
     25#include "rp_tcloptions.h"
    2526
    2627/*
     
    4849
    4950typedef RpOptimStatus (RpOptimHandler) _ANSI_ARGS_((
    50     struct RpOptimEnv *envPtr, RpOptimEvaluator *evalProc));
     51    struct RpOptimEnv *envPtr, RpOptimEvaluator *evalProc,
     52    char *fitnessExpr));
     53
     54/*
     55 * Each optimization package is plugged in to this infrastructure
     56 * by defining the following data at the top of rp_optimizer_tcl.c
     57 */
     58typedef struct RpOptimPlugin {
     59    char *name;                   /* name of this package for -using */
     60    RpOptimInit *initProc;        /* initialization routine */
     61    RpOptimHandler *runProc;      /* handles the core optimization */
     62    RpOptimCleanup *cleanupProc;  /* cleanup routine */
     63    RpTclOption *optionSpec;      /* specs for config options */
     64} RpOptimPlugin;
    5165
    5266/*
     
    98112 */
    99113typedef struct RpOptimEnv {
     114    RpOptimPlugin *pluginDefn;      /* plug-in handling this optimization */
     115    ClientData pluginData;          /* data created by plugin init routine */
    100116    RpOptimEvaluator *evalProc;     /* called during optimization to do run */
    101     ClientData pluginData;          /* data created by plugin init routine */
    102     RpOptimCleanup *cleanupProc;    /* cleanup routine for pluginData */
     117    char *fitnessExpr;              /* fitness function in string form */
    103118    ClientData toolData;            /* data used during tool execution */
    104119    RpOptimParam **paramList;       /* list of input parameters to vary */
     
    110125 *  Here are the functions in the API:
    111126 */
    112 EXTERN RpOptimEnv* RpOptimCreate _ANSI_ARGS_((ClientData pluginData,
    113     RpOptimCleanup *cleanupProc));
     127EXTERN RpOptimEnv* RpOptimCreate _ANSI_ARGS_((RpOptimPlugin *pluginDefn));
    114128
    115129EXTERN RpOptimParam* RpOptimAddParamNumber _ANSI_ARGS_((RpOptimEnv *envPtr,
  • trunk/optimizer/src/rp_optimizer_tcl.c

    r898 r899  
    1515 */
    1616#include "rp_optimizer.h"
    17 #include "rp_optimizer_plugin.h"
    1817
    1918/*
     
    3534};
    3635
    37 typedef struct RpOptimPluginData {
    38     RpOptimPlugin *pluginDefn;      /* points back to plugin definition */
    39     ClientData clientData;          /* data needed for particular plugin */
    40 } RpOptimPluginData;
    41 
    4236typedef struct RpOptimToolData {
    4337    Tcl_Interp *interp;             /* interp handling this tool */
     
    6761static int RpOptimInstanceCmd _ANSI_ARGS_((ClientData clientData,
    6862    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
    69 static void RpOptimInstanceCleanup _ANSI_ARGS_((ClientData cdata));
    7063static RpOptimStatus RpOptimizerPerformInTcl _ANSI_ARGS_((RpOptimEnv *envPtr,
    7164    RpOptimParam *values, int numValues, double *fitnessPtr));
    72 static int RpOptimizerUpdateInTcl _ANSI_ARGS_((RpOptimEnv *envPtr));
    7365
    7466#ifdef BUILD_Rappture
     
    129121    RpOptimEnv* envPtr;
    130122    RpOptimPlugin* pluginPtr;
    131     RpOptimPluginData* pluginDataPtr;
    132123    RpOptimToolData* toolDataPtr;
    133124
     
    222213     * Create an optimizer and install a Tcl command to access it.
    223214     */
    224     pluginDataPtr = (RpOptimPluginData*)malloc(sizeof(RpOptimPluginData));
    225     pluginDataPtr->pluginDefn = usingPluginPtr;
    226     pluginDataPtr->clientData = NULL;
    227     if (usingPluginPtr->initProc) {
    228         pluginDataPtr->clientData = (*usingPluginPtr->initProc)();
    229     }
    230     envPtr = RpOptimCreate((ClientData)pluginDataPtr, RpOptimInstanceCleanup);
     215    envPtr = RpOptimCreate(usingPluginPtr);
    231216
    232217    toolDataPtr = (RpOptimToolData*)malloc(sizeof(RpOptimToolData));
     
    298283 *      <name> get ?<glob>? ?-option?
    299284 *      <name> configure ?-option? ?value -option value ...?
    300  *      <name> perform ?-tool <tool>? ?-updatecommand <varName>?
     285 *      <name> perform ?-tool <tool>? ?-fitness <expr>? \
     286 *                     ?-updatecommand <varName>?
    301287 *      <name> using
    302288 *
     
    314300{
    315301    RpOptimEnv* envPtr = (RpOptimEnv*)cdata;
    316     RpOptimPluginData* pluginDataPtr = (RpOptimPluginData*)envPtr->pluginData;
    317302    RpOptimToolData* toolDataPtr = (RpOptimToolData*)envPtr->toolData;
    318303
    319304    int n, j, nvals, nmatches;
    320     char *option, *type, *path;
     305    char *option, *type, *path, *fitnessExpr;
    321306    RpOptimParam *paramPtr;
    322307    RpOptimParamString *strPtr;
     
    510495     */
    511496    else if (*option == 'c' && strcmp(option,"configure") == 0) {
    512         optSpecPtr = pluginDataPtr->pluginDefn->optionSpec;
     497        optSpecPtr = envPtr->pluginDefn->optionSpec;
    513498        if (objc == 2) {
    514499            /* report all values: -option val -option val ... */
     
    519504            for (n=0; optSpecPtr[n].optname; n++) {
    520505                if (RpTclOptionGet(interp, optSpecPtr,
    521                     (ClientData)pluginDataPtr->clientData,
     506                    (ClientData)envPtr->pluginData,
    522507                    optSpecPtr[n].optname) != TCL_OK) {
    523508                    Tcl_DecrRefCount(rval);
     
    543528            option = Tcl_GetStringFromObj(objv[2], (int*)NULL);
    544529            return RpTclOptionGet(interp, optSpecPtr,
    545                 (ClientData)pluginDataPtr->clientData, option);
     530                (ClientData)envPtr->pluginData, option);
    546531        }
    547532        else {
    548533            return RpTclOptionsProcess(interp, objc-2, objv+2,
    549                 optSpecPtr, pluginDataPtr->clientData);
    550         }
    551     }
    552 
    553     /*
    554      * OPTION:  perform ?-tool name? ?-updatecommand name?
     534                optSpecPtr, envPtr->pluginData);
     535        }
     536    }
     537
     538    /*
     539     * OPTION:  perform ?-tool name? ?-fitness expr? ?-updatecommand name?
    555540     */
    556541    else if (*option == 'p' && strcmp(option,"perform") == 0) {
    557542        /* use this tool by default */
    558543        toolPtr = toolDataPtr->toolPtr;
     544
     545        /* no -fitness function by default */
     546        fitnessExpr = NULL;
    559547
    560548        /* no -updatecommand by default */
     
    574562                n += 2;
    575563            }
     564            else if (strcmp(option,"-fitness") == 0) {
     565                fitnessExpr = Tcl_GetStringFromObj(objv[n+1], (int*)NULL);
     566                n += 2;
     567            }
    576568            else if (strcmp(option,"-updatecommand") == 0) {
    577569                updateCmdPtr = objv[n+1];
     
    580572            else {
    581573                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
    582                     "bad option \"", option, "\": should be -tool,"
     574                    "bad option \"", option, "\": should be -fitness, -tool,"
    583575                    " -updatecommand", (char*)NULL);
    584576                return TCL_ERROR;
     
    587579
    588580        /*
    589          * Must have a tool object at this point, or else we
    590          * don't know what to optimize.
     581         * Must have a tool object and a fitness function at this point,
     582         * or else we don't know what to optimize.
    591583         */
    592584        if (toolPtr == NULL) {
     
    596588            return TCL_ERROR;
    597589        }
     590        if (fitnessExpr == NULL) {
     591            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
     592                "missing -fitness function for optimization",
     593                (char*)NULL);
     594            return TCL_ERROR;
     595        }
    598596
    599597        Tcl_IncrRefCount(toolPtr);
     
    604602
    605603        /* call the main optimization routine here */
    606         status = (*pluginDataPtr->pluginDefn->runProc)(envPtr,
    607             RpOptimizerPerformInTcl);
     604        status = (*envPtr->pluginDefn->runProc)(envPtr,
     605            RpOptimizerPerformInTcl, fitnessExpr);
    608606
    609607        Tcl_DecrRefCount(toolPtr);
     
    639637            return TCL_ERROR;
    640638        }
    641         Tcl_SetResult(interp, pluginDataPtr->pluginDefn->name, TCL_STATIC);
     639        Tcl_SetResult(interp, envPtr->pluginDefn->name, TCL_STATIC);
    642640        return TCL_OK;
    643641    }
     
    650648    }
    651649    return TCL_OK;
    652 }
    653 
    654 /*
    655  * ----------------------------------------------------------------------
    656  * RpOptimInstanceCleanup()
    657  *
    658  * Called whenever a optimizer environment is being delete to clean
    659  * up any plugin data associated with it.  It's a little convoluted.
    660  * Here's the sequence:  A Tcl command is deleted, RpOptimCmdDelete()
    661  * gets called to clean it up, RpOptimDelete() is called within that,
    662  * and this method gets called to clean up the client data associated
    663  * with the underlying environment.
    664  * ----------------------------------------------------------------------
    665  */
    666 static void
    667 RpOptimInstanceCleanup(cdata)
    668     ClientData cdata;   /* plugin data being deleted */
    669 {
    670     RpOptimPluginData *pluginDataPtr = (RpOptimPluginData*)cdata;
    671 
    672     /* if there are config options, clean them up first */
    673     if (pluginDataPtr->pluginDefn->optionSpec) {
    674         RpTclOptionsCleanup(pluginDataPtr->pluginDefn->optionSpec,
    675             pluginDataPtr->clientData);
    676     }
    677 
    678     /* call a specialized cleanup routine to handle the rest */
    679     if (pluginDataPtr->pluginDefn->cleanupProc) {
    680         (*pluginDataPtr->pluginDefn->cleanupProc)(pluginDataPtr->clientData);
    681     }
    682     pluginDataPtr->clientData = NULL;
    683 
    684     /* free the container */
    685     free((char*)pluginDataPtr);
    686650}
    687651
     
    706670    double *fitnessPtr;       /* returns: computed value of fitness func */
    707671{
    708     printf("running...\n");
    709     *fitnessPtr = 0.0;
    710     return RP_OPTIM_SUCCESS;
    711 }
    712 
    713 /*
    714  * ------------------------------------------------------------------------
    715  *  RpOptimizerUpdateInTcl()
    716  *
    717  *  Invoked as a call-back within RpOptimPerform() to update the
    718  *  application and look for an "abort" signal.  Evaluates a bit of
    719  *  optional code stored in the optimization environment.  Returns 0
    720  *  if everything is okay, and non-zero if the user wants to abort.
    721  * ------------------------------------------------------------------------
    722  */
    723 static int
    724 RpOptimizerUpdateInTcl(envPtr)
    725     RpOptimEnv *envPtr;       /* optimization environment */
    726 {
     672    RpOptimStatus result = RP_OPTIM_SUCCESS;
    727673    RpOptimToolData *toolDataPtr = (RpOptimToolData*)envPtr->toolData;
    728     int status;
    729 
     674    Tcl_Interp *interp = toolDataPtr->interp;
     675    int n, status;
     676#define MAXBUILTIN 10
     677    int objc; Tcl_Obj **objv, *storage[MAXBUILTIN], *getcmd[3];
     678    int rc; Tcl_Obj **rv;
     679    Tcl_Obj *dataPtr;
     680    char *out;
     681
     682    /*
     683     * Set up the arguments for a Tcl evaluation.
     684     */
     685    objc = 2*numValues + 2;  /* "tool run" + (name value)*numValues */
     686    if (objc > MAXBUILTIN) {
     687        objv = (Tcl_Obj**)malloc(objc*sizeof(Tcl_Obj));
     688    } else {
     689        objv = storage;
     690    }
     691    objv[0] = toolDataPtr->toolPtr;
     692    objv[1] = Tcl_NewStringObj("run",-1); Tcl_IncrRefCount(objv[1]);
     693    for (n=0; n < numValues; n++) {
     694        objv[2*n+2] = Tcl_NewStringObj(values[n].name, -1);
     695        Tcl_IncrRefCount(objv[2*n+2]);
     696
     697        switch (values[n].type) {
     698        case RP_OPTIMPARAM_NUMBER:
     699            objv[2*n+3] = Tcl_NewDoubleObj(values[n].value.dval);
     700            Tcl_IncrRefCount(objv[2*n+3]);
     701            break;
     702        case RP_OPTIMPARAM_STRING:
     703            objv[2*n+3] = Tcl_NewStringObj(values[n].value.sval.str,-1);
     704            Tcl_IncrRefCount(objv[2*n+3]);
     705            break;
     706        default:
     707            panic("bad parameter type in RpOptimizerPerformInTcl()");
     708        }
     709    }
     710
     711    /*
     712     *  Invoke the tool and pick apart its results.
     713     */
     714    status = Tcl_EvalObjv(interp, objc, objv, TCL_EVAL_GLOBAL);
     715
     716    if (status != TCL_OK) {
     717        result = RP_OPTIM_FAILURE;
     718        fprintf(stderr, "== JOB FAILED: %s\n", Tcl_GetStringResult(interp));
     719    } else {
     720        dataPtr = Tcl_GetObjResult(interp);
     721        /* hang on to this while we pick it apart into rv[] */
     722        Tcl_IncrRefCount(dataPtr);
     723
     724        if (Tcl_ListObjGetElements(interp, dataPtr, &rc, &rv) != TCL_OK) {
     725            result = RP_OPTIM_FAILURE;
     726            fprintf(stderr, "== JOB FAILED: %s\n", Tcl_GetStringResult(interp));
     727        } else if (rc != 2
     728                    || Tcl_GetIntFromObj(interp, rv[0], &status) != TCL_OK) {
     729            result = RP_OPTIM_FAILURE;
     730            fprintf(stderr, "== JOB FAILED: malformed result: expected {status output}\n");
     731        } else {
     732            out = Tcl_GetStringFromObj(rv[1], (int*)NULL);
     733            if (status != 0) {
     734                result = RP_OPTIM_FAILURE;
     735                fprintf(stderr, "== JOB FAILED with status code %d:\n%s\n",
     736                    status, out);
     737            } else {
     738                /*
     739                 *  Get the output value from the tool output in the
     740                 *  result we just parsed above:  {status xmlobj}
     741                 *
     742                 *  Eventually, we should write a whole parser to
     743                 *  handle arbitrary fitness functions.  For now,
     744                 *  just query a single output value by calling:
     745                 *    xmlobj get fitnessExpr
     746                 */
     747                getcmd[0] = rv[1];
     748                getcmd[1] = Tcl_NewStringObj("get",-1);
     749                getcmd[2] = Tcl_NewStringObj(envPtr->fitnessExpr,-1);
     750                for (n=0; n < 3; n++) {
     751                    Tcl_IncrRefCount(getcmd[n]);
     752                }
     753
     754                status = Tcl_EvalObjv(interp, 3, getcmd, TCL_EVAL_GLOBAL);
     755
     756                if (status != TCL_OK) {
     757                    result = RP_OPTIM_FAILURE;
     758                    fprintf(stderr, "== UNEXPECTED ERROR while extracting output value:%s\n", Tcl_GetStringResult(interp));
     759                } else if (Tcl_GetDoubleFromObj(interp,
     760                      Tcl_GetObjResult(interp), fitnessPtr) != TCL_OK) {
     761                    result = RP_OPTIM_FAILURE;
     762                    fprintf(stderr, "== ERROR while extracting output value:%s\n", Tcl_GetStringResult(interp));
     763                }
     764                for (n=0; n < 3; n++) {
     765                    Tcl_DecrRefCount(getcmd[n]);
     766                }
     767            }
     768        }
     769        Tcl_DecrRefCount(dataPtr);
     770    }
     771
     772    /*
     773     * Clean up objects created for command invocation.
     774     */
     775    for (n=1; n < objc; n++) {
     776        Tcl_DecrRefCount(objv[n]);
     777    }
     778    if (objv != storage) {
     779        free(objv);
     780    }
     781
     782    /*
     783     * If there's the -updatecommand was specified, execute it here
     784     * to bring the application up-to-date and see if the user wants
     785     * to abort.
     786     */
    730787    if (toolDataPtr->updateCmdPtr) {
    731788        status = Tcl_GlobalEvalObj(toolDataPtr->interp,
     
    734791        if (status == TCL_ERROR) {
    735792            Tcl_BackgroundError(toolDataPtr->interp);
    736             return 0;
    737         }
    738         if (status == TCL_BREAK || status == TCL_RETURN) {
    739             return 1;  /* abort! */
    740         }
    741     }
    742     return 0;  /* keep going... */
     793        }
     794        else if (status == TCL_BREAK || status == TCL_RETURN) {
     795            return RP_OPTIM_ABORTED;
     796        }
     797    }
     798    return RP_OPTIM_SUCCESS;
    743799}
Note: See TracChangeset for help on using the changeset viewer.