¿Qué estrategias de programación puedo tomar para modificar fácilmente los parámetros del algoritmo?

17

El desarrollo de algoritmos científicos es un proceso altamente iterativo que a menudo implica cambiar muchos parámetros que querré variar, ya sea como parte de mi diseño experimental o como parte del ajuste del rendimiento del algoritmo. ¿Qué estrategias puedo tomar para estructurar estos parámetros para que pueda cambiarlos fácilmente entre iteraciones y para poder agregar nuevos fácilmente?

Scottie T
fuente

Respuestas:

14

Es engorroso para el usuario especificar cada aspecto de un algoritmo. Si el algoritmo permite componentes anidados, entonces no sería suficiente un número finito de opciones. Por lo tanto, es crítico que las opciones no necesariamente "suban" al nivel superior, como en el caso de argumentos explícitos o parámetros de plantilla. Esto a veces se llama el "problema de configuración" en ingeniería de software. Creo que PETSc tiene un sistema único y poderoso para la gestión de la configuración. Es similar al patrón del Localizador de servicios en el ensayo de Martin Fowler sobre inversión de control .

El sistema de configuración de PETSc funciona a través de una combinación de configuración especificada por el usuario administrada por los objetos solucionadores (con consultas get y set) y la base de datos de opciones. Cualquier componente de la simulación puede declarar una opción de configuración, un valor predeterminado y un lugar para colocar el resultado. Los objetos anidados tienen prefijos que se pueden componer, de modo que cada objeto que necesita configuración se puede abordar de forma independiente. Las opciones en sí pueden leerse desde la línea de comandos, el entorno, los archivos de configuración o desde el código. Cuando se declara una opción, se especifican una cadena de ayuda y una página de manual, de modo que la -helpopción sea comprensible y se pueda escribir una GUI correctamente vinculada.

El usuario llama a un SetFromOptionsmétodo para hacer que un objeto se configure según las opciones de la línea de comandos. Llamar a esta función es opcional y no se puede llamar si el usuario (persona que escribe el código que llama a PETSc) está exponiendo las opciones a través de alguna otra interfaz. Recomendamos encarecidamente que el usuario exponga la base de datos de opciones porque le da al usuario final (persona que ejecuta la aplicación) una gran cantidad de poder, pero no es obligatorio.

Una configuración típica, llamada vía

PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol",                                      /* options database key */
                 "Absolute tolerance for local truncation error", /* long description */
                 "TSSetTolerances",                               /* function and man page on topic */
                  ts->atol,                                       /* current/default value *?
                  &ts->atol,                                      /* place to store value */
                  &option_set);                                   /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
                 defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt);                                 /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes);                                     /* configure nonlinear solver. */
PetscOptionsEnd();

Notas:

  • PetscOptionsList()presenta al usuario una opción de una lista dinámica. Existe una arquitectura de complementos que las nuevas implementaciones pueden usar para exponerse como de primera clase a las personas que llaman. (Estas implementaciones pueden colocarse en bibliotecas compartidas y usarse como de primera clase sin volver a compilar programas).
  • SNESSetFromOptions() configura recursivamente los solucionadores lineales, preacondicionadores y cualquier otro componente que necesite configuración.
Jed Brown
fuente
11

Me he enfrentado a este problema varias veces al desarrollar mis propios códigos de simulación desde cero: qué parámetros deben ir en un archivo de entrada, que deben tomarse de la línea de comando, etc. Después de experimentar un poco, lo siguiente resultó ser eficiente. (No es tan avanzado como PETSc.)

En lugar de escribir un 'programa' de simulación experimental, estoy más inclinado a escribir un paquete de Python que contenga todas las funciones y clases necesarias para ejecutar la simulación. El archivo de entrada tradicional se reemplaza por un pequeño script de Python con 5 a 10 líneas de código. Algunas líneas suelen estar relacionadas con la carga de archivos de datos y la especificación de resultados. Otros son instrucciones para el cálculo real. Los buenos valores predeterminados para argumentos opcionales en el paquete Python hacen posible que los principiantes usen la biblioteca para simulaciones simples, mientras que el usuario avanzado aún tiene acceso a todas las campanas y silbatos.

Algunos ejemplos:

Toon Verstraelen
fuente
Esto es genial, pero creo que es ortogonal al problema de configuración. Si necesita especificar un algoritmo jerárquico o anidado, entonces tiene opciones para especificar para muchos objetos internos. El código que los llama realmente no debería siquiera saber acerca de su existencia porque la cantidad de niveles y los tipos de anidamiento pueden cambiar. Este es el problema de todas esas opciones "burbujeando". Con su código Python de alto nivel, puede hacer que sea "fácil" especificar esas opciones, pero aún debe especificarlas en el código. Creo que generalmente no es algo bueno.
Jed Brown
xmonad usa este método para configurar su administrador de ventanas para X.
rcollyer
2

Como primer punto, haría el algoritmo Y el software lo más general posible. Aprendí esto de la manera difícil.

Digamos que comienzas con un caso de prueba simple. Puedes hacer esto más rápido. Pero luego, si hizo que el software sea demasiado específico (muy pocos parámetros) para este caso inicial, perderá más y más tiempo adaptándolo cada vez que agregue un nuevo grado de libertad. Lo que hago ahora es pasar más tiempo al principio haciendo que la cosa sea bastante general y aumentando la variación de los parámetros a medida que avanzo.

Esto implica más pruebas desde el principio, ya que tendrá más parámetros desde el punto de partida, pero significará que luego puede jugar mucho con el algoritmo a cero o a un costo muy bajo.

Ejemplo: el algoritmo implica calcular la integral de superficie del producto escalar de dos funciones vectoriales. No asuma desde el principio el tamaño, la geometría y la discretización de la superficie si en el futuro desea cambiar eso. Haga una función de producto punto, haga que la superficie sea lo más general posible, calcule la integral de una manera formal agradable. Puede probar cada función que realice por separado.

Al principio, puede y comenzar a integrarse sobre geometrías simples y declarar muchos parámetros al principio como constantes. A medida que pasa el tiempo, si desea cambiar la geometría, puede hacerlo fácilmente. Si hubiera hecho suposiciones al principio, tendría que cambiar todo el código cada vez.

jbcolmenares
fuente