unit-testing - unitarias - unit test c# visual studio 2017
¿Cómo debo probar un algoritmo genético? (10)
Bueno, la parte más comprobable es la función de acondicionamiento físico, donde estará toda su lógica. esto puede ser en algunos casos bastante complejo (puede que esté ejecutando todo tipo de simulaciones basadas en parámetros de entrada) por lo que quiere estar seguro de que todo eso funciona con muchas pruebas unitarias, y este trabajo puede seguir cualquier metodología.
Con respecto a probar los parámetros de GA (tasa de mutación, estrategia cruzada, lo que sea) si estás implementando eso tú mismo, puedes probarlo (puedes volver a tener pruebas unitarias sobre la lógica de la mutación, etc.) pero no estarás capaz de probar el "ajuste fino" de la GA.
En otras palabras, no podrá probar si GA se desempeña de otra manera que no sea por la bondad de las soluciones encontradas.
He hecho unos pocos algoritmos genéticos; funcionan (encuentran una solución razonable rápidamente). Pero ahora descubrí TDD . ¿Hay alguna manera de escribir un algoritmo genético (que depende en gran medida de números aleatorios) de una manera TDD?
Para plantear la pregunta de manera más general, ¿Cómo se prueba un método / función no determinista? Esto es lo que he pensado:
Usa una semilla específica Lo cual no ayudará si cometo un error en el código en primer lugar, pero ayudará a encontrar errores al refactorizar.
Use una lista conocida de números. Similar a lo anterior, pero podría seguir el código a mano (lo cual sería muy tedioso).
Use un número constante. Al menos sé qué esperar. Sería bueno asegurarse de que un dado siempre lea 6 cuando RandomFloat (0,1) siempre devuelve 1.
Intente mover la mayor parte del código no determinista de la GA como sea posible. que parece tonto ya que ese es el núcleo de su propósito.
También se apreciarán enlaces a muy buenos libros sobre pruebas.
Escribí una aplicación didáctica del algoritmo genético C # TDD: http://code.google.com/p/evo-lisa-clone/
Tomemos el método de resultado aleatorio más simple en la aplicación: PointGenetics.Create, que crea un punto aleatorio, dados los límites. Para este método, utilicé 5 pruebas, y ninguna de ellas se basa en una semilla específica:
La prueba de aleatoriedad es simple: para un límite grande (muchas posibilidades), dos puntos generados consecutivamente no deberían ser iguales. Las pruebas restantes verifican otras restricciones.
Me parece que la única manera de probar su lógica consistente es aplicar una entrada consistente , ... o tratar cada iteración como un autómata único cuyo estado se prueba antes y después de esa iteración, convirtiendo el sistema no determinista general en componentes comprobables basados en deterministas valores de iteración.
Para variaciones / herencia / herencia de atributos en iteraciones, pruebe esos valores en los límites de cada iteración y pruebe la salida global de todas las iteraciones basándose en la entrada / salida conocida de las subtests de iteración exitosas ...
Debido a que el algoritmo es iterativo puede usar la inducción en su prueba para garantizar que funcione durante 1 iteración, n + 1 iteraciones para demostrar que producirá resultados correctos (independientemente del determinismo de datos) para un rango / dominio de entrada dado y las restricciones sobre valores posibles en la entrada.
Editar Encontré estas estrategias para probar sistemas no deterministas que podrían proporcionar alguna información. Podría ser útil para el análisis estadístico de los resultados en vivo una vez que el proceso TDD / desarrollo demuestre que la lógica es sólida.
Podría escribir una red neuronal redundante para analizar los resultados de su algoritmo y clasificar el resultado en función de los resultados esperados. :)
Rompe tu método tanto como puedas. Luego, también puede realizar una prueba unitaria alrededor de la parte aleatoria para verificar el rango de valores. Incluso haga que la prueba se ejecute varias veces para ver si el resultado cambia.
Probaría las funciones aleatorias probándolas varias veces y analizando si la distribución de los valores de retorno cumple con las expectativas estadísticas (esto implica cierto conocimiento estadístico).
Si está hablando de TDD, definitivamente comenzaría seleccionando un número constante y haciendo crecer su suite de pruebas desde allí. He hecho TDD en algunos problemas altamente matemáticos y es útil tener algunos casos constantes que conoces y que hayas resuelto a mano para ejecutar desde el principio.
W / R / T su 4º punto, sacando el código no determinista de la Asamblea General, creo que este es probablemente un enfoque que vale la pena considerar. Si puede descomponer el algoritmo y separar las preocupaciones no deterministas, debería hacer que probar las partes deterministas sea sencillo. Siempre y cuando tengas cuidado acerca de cómo nombras las cosas, no creo que estés sacrificando mucho aquí. A menos que te esté malinterpretando, la AG todavía delegará en este código, pero vive en otro lado.
En cuanto a enlaces a muy buenos libros sobre pruebas (de desarrollador), mis favoritos son:
- Prueba conducida por Lasse Kosela
- Trabajando eficazmente con Legacy Code por Michael Feathers
- XUnit Test Patterns por Gerard Meszaros
- Pruebas Java ™ de próxima generación: TestNG y conceptos avanzados por Cédric Beust y Hani Suleiman
Sugeriría encarecidamente investigar el uso de objetos simulados para los casos de prueba de la unidad ( http://en.wikipedia.org/wiki/Mock_object ). Puede usarlos para simular objetos que hacen suposiciones aleatorias para provocar que obtenga los resultados esperados.
Todas sus funciones deben ser completamente deterministas. Esto significa que ninguna de las funciones que está probando debe generar el número aleatorio dentro de la función en sí. Querrá pasar eso como un parámetro. De esta forma, cuando su programa tome decisiones basadas en sus números aleatorios, puede pasar números representativos para probar el resultado esperado para ese número. Lo único que no debería ser determinista es su generador de números aleatorios real, del cual no necesita preocuparse demasiado porque no debería escribirlo usted mismo. Debería poder asumir que funciona siempre que sea una biblioteca establecida.
Eso es para tus pruebas unitarias. Para sus pruebas de integración, si lo hace, puede buscar burlarse de su generación de números aleatorios, reemplazándola con un algoritmo que devolverá números conocidos de 0..n por cada número aleatorio que necesite generar.
Una forma en que hago para la prueba unitaria de funciones no deterministas de algoritmos GA es poner la elección de números aleatorios en una función diferente de la lógica que usa números aleatorios.
Por ejemplo, si tiene una función que toma un gen (vector de algo) y toma dos puntos aleatorios del gen para hacer algo con ellos (mutación o lo que sea), puede poner la generación de los números aleatorios en una función, y luego páselos junto con el gen a otra función que contenga la lógica dado que los números.
De esta forma puedes hacer TDD con la función lógica y pasarle ciertos genes y ciertos números, sabiendo exactamente qué debería hacer la lógica en el gen dado que los números y la capacidad de escribir afirman sobre el gen modificado.
Otra forma de probar con la generación de números aleatorios es externalizar esa generación a otra clase, a la que se pueda acceder a través de un contexto o cargar desde un valor de configuración, y usar una diferente para las ejecuciones de prueba. Habría dos implementaciones de esa clase, una para producción que genera números aleatorios reales y otra para pruebas, que tendría formas de aceptar los números que luego generaría. Luego, en la prueba, puede proporcionar ciertos números que la clase proporcionará al código probado.
Una prueba de que el algoritmo le da el mismo resultado para la misma entrada podría ayudarlo, pero a veces hará cambios que cambien el comportamiento de selección de resultados del algoritmo.
Me esforzaría al máximo para realizar una prueba que garantice que el algoritmo le proporcione un resultado correcto. Si el algoritmo le da un resultado correcto para un número de semillas estáticas y valores aleatorios, el algoritmo funciona o no se rompe a través de los cambios realizados.
Otra posibilidad en TDD es la posibilidad de evaluar el algoritmo. Si puede verificar automáticamente qué tan bueno es el resultado, puede agregar pruebas que demuestren que un cambio no ha disminuido las cualidades de sus resultados o aumentado su tiempo de cálculo de manera irracional.
Si quieres probar tu algoritmo con muchas semillas base, tal vez quieras tener que probar una sola armadura que ejecuta una prueba rápida para comenzar después de cada salvada para asegurarte de que no has roto nada y un palo que se ejecuta durante más tiempo para una evaluación posterior