Muchos algoritmos numéricos (integración, diferenciación, interpolación, funciones especiales, etc.) están disponibles en bibliotecas de computación científica como GSL . Pero a menudo veo código con implementaciones "enrolladas a mano" de estas funciones. Para los programas pequeños que no están destinados necesariamente a la distribución pública, ¿es una práctica común entre los científicos informáticos implementar solo algoritmos numéricos (con lo que me refiero a copiar o transcribir desde un sitio web, recetas numéricas o similares) cuando los necesite? Si es así, ¿hay alguna razón particular para evitar vincularse a algo como GSL, o es simplemente más "tradición" que otra cosa?
Pregunto porque soy un gran admirador de la reutilización de código , lo que sugiere que debería intentar usar implementaciones existentes cuando sea posible. Pero tengo curiosidad por saber si hay razones por las cuales ese principio es menos valioso en la computación científica que en la programación general.
Olvidé mencionar: estoy preguntando específicamente sobre C y C ++, a diferencia de los lenguajes como Python, donde hay un beneficio claro (velocidad de ejecución) para usar una biblioteca.
Respuestas:
Solía implementar todo yo mismo, pero últimamente he comenzado a usar bibliotecas mucho más. Creo que hay varias ventajas muy importantes de usar una biblioteca, más allá de la cuestión de si tiene que escribir una rutina usted mismo o no. Si usas una biblioteca, obtienes
En el último punto anterior, estoy pensando en grandes bibliotecas como Trilinos o PETSc . Puedo reforzar esto con un par de ejemplos personales concretos en el desarrollo de PyClaw . Aunque hubiera sido sencillo paralelizar Clawpack con llamadas MPI, elegimos usar PETSc. Esto nos permitió limitar el código paralelo en el paquete a menos de 300 líneas de Python, pero aún mejor, al poner nuestros datos en el formato de PETSc obtuvimos acceso inmediato a los solucionadores implícitos de PETSc, permitiendo el trabajo actual en un solucionador implícito en PyClaw. Como segundo ejemplo, PyClaw inicialmente incluyó la reconstrucción WENO de quinto orden con código de mano, pero finalmente decidimos confiar en PyWENOpaquete para esto. Esta fue una gran ganancia, ya que PyWENO puede generar automáticamente rutinas WENO de cualquier orden en varios idiomas.
Finalmente, si usa bibliotecas, puede contribuir de nuevo desarrollando mejoras o encontrando errores, lo que beneficiará a muchas otras personas, mientras que depurar o mejorar su propio código solo lo beneficia a usted.
fuente
Hay una sobrecarga considerable del programador involucrada en el enlace a una función de biblioteca, especialmente si esa biblioteca es nueva para el programador. A menudo es más simple reescribir algoritmos simples en lugar de descubrir los detalles de una biblioteca en particular. A medida que los algoritmos se vuelven más complejos, este comportamiento cambia.
Python se ha destacado en la reducción de esta sobrecarga con herramientas como pip / easy_install y una interfaz de estructura de datos uniforme (es decir, cada biblioteca parece tomar y producir una matriz numpy).
fuente
Uno de los proyectos en los que estoy involucrado en este momento es escribir un paquete flexible de simulación y análisis para una clase de detectores de física de partículas. Uno de los objetivos de este proyecto es proporcionar la base de código que se utilizará en estas cosas en las próximas décadas.
En este punto, ya tenemos dos docenas de dependencias, lo que hace que el proceso de compilación sea una pesadilla que ha derivado de un proyecto separado administrado desde el centro de computación de Fermilab solo para proporcionar una cadena de herramientas confiable.
Ahora imagine que encuentra la necesidad de alguna herramienta que no está en esa cadena de herramientas (me ocurrió el mes pasado). Tienes tres opciones
Es muy fácil elegir (1). Quizás demasiado fácil.
fuente
Creo que es bastante común, con algunos algoritmos más propensos a volver a implementarse que otros.
Hay una complicada compensación entre lo molesto que es instalar una biblioteca, lo difícil que es implementar el algoritmo usted mismo, lo difícil que es optimizarlo y lo bien que la biblioteca se adapta a sus necesidades. Además, a veces usar una biblioteca es una exageración: utilicé el algoritmo de bisección lenta en uno de mis programas porque lo llamé solo unas pocas veces y no quería agregar una biblioteca solo por eso.
¿Le resulta fácil escribir una versión bien optimizada? Si es así, es mejor que lo hagas. Obtendrá exactamente lo que necesita y no dependerá del trabajo de nadie. Pero, por supuesto, realmente necesita saber lo que está haciendo: incluso los algoritmos simples pueden ser difíciles de implementar.
Sería curioso ver un estudio sobre esto, pero desde mi perspectiva parcial, los científicos a menudo usan bibliotecas para álgebra lineal y generadores de números aleatorios, y la mayoría del código restante es casero.
fuente
Creo que implementar un algoritmo en lugar de usar una biblioteca a veces puede proporcionar una mejor comprensión y control del modelo. Cuando estoy codificando algún programa para cálculos científicos, es importante para mí entender lo que estoy haciendo. La implementación de los algoritmos importantes me ayuda a conocer mejor el problema y lograr un mejor control del mismo.
Por otro lado, a veces no es una tarea trivial seleccionar una biblioteca que sea necesaria para obtener una solución, por lo que es mejor buscar algoritmos ya implementados cuando esté seguro de qué está tratando de lograr y por qué lo quiere.
Si los algoritmos son complejos, codificarlos a mano le brinda la oportunidad de mejorar el rendimiento / la calidad de la solución utilizando funciones específicas de la tarea. Y a veces es necesario cambiar un poco el algoritmo, lo cual es más fácil si conoce el código que escribió y puede editarlo de la manera que desee.
fuente
Una respuesta es que hay tantas pequeñas variaciones en el código numérico que es realmente difícil encapsularlo en una biblioteca. Tome esto en comparación con el software web, que a menudo es fácil de instalar y tiene un conjunto claro de entradas y salidas. Creo que lo más común es que las personas agarren un marco, o una gran biblioteca que actúa como un marco (Trilinos / PETSc), y que usan ese ecosistema para obtener los beneficios de usar códigos comunitarios.
fuente
Antes de decidir si usar o no bibliotecas, creo que también querrás saber cuánto ayudará el uso de una biblioteca a tu código. Si va a utilizar una biblioteca bien optimizada para un núcleo computacional clave, entonces probablemente sea mucho más eficiente que intentar escribir el suyo propio.
Sin embargo, si está escribiendo una rutina especializada que solo se llamará una vez durante la ejecución de un programa, puede que no valga la pena adaptar su código para que se ajuste al marco requerido por una biblioteca.
(Otra cosa a tener en cuenta: ¿cuánto tendrá que rediseñar para aprovechar la biblioteca? A menos que las horas de trabajo que dedica a reparar el código se compensen con las ganancias correspondientes en eficiencia o precisión numérica, es posible que no vale la pena a largo plazo. Sin embargo, idealmente, esto es algo que se planifica al diseñar inicialmente estructuras de datos y algoritmos, de modo que el "flujo" de la biblioteca se tenga en cuenta desde cero).
fuente
Mis 2 centavos
Creo que es más fácil escribir en general sobre esto, en lugar de solo sobre C / C ++. Primero, las bibliotecas en lenguajes como Python no se usan necesariamente para obtener un beneficio de velocidad, incluso si eso es una consecuencia. Creo que @David cubrió las razones bastante bien.
Tomándolo desde arriba, la implementación del lenguaje en cierta medida dicta a qué bibliotecas tiene acceso. Los lenguajes de uso común en ciencia computacional incluyen C, C ++, Python, Perl, Java, Fortran y R. Ejemplos menos comunes pueden ser Ocaml y Common Lisp. Ahora, dado que la mayoría de estos lenguajes están escritos en C, tienen una interfaz de función externa natural para C. Sin embargo, no es tan fácil llamar, por ejemplo, una biblioteca Perl de Python o viceversa. Entonces, en la práctica, las personas tienden a
Use una biblioteca escrita en su lenguaje de implementación, usualmente algo que es parte de las bibliotecas estándar, o de otra manera ampliamente disponible, o
Llame a una biblioteca C / C ++ a través de los idiomas FFI. Esto supone que todavía no existe un contenedor, ya que si lo hace, no se puede distinguir fácilmente de (1).
(2) suele ser más difícil, ya que debe ajustar la función C / C ++ usted mismo. Además, debe agrupar la biblioteca o agregar una dependencia adicional. Por esa razón, es más probable que las personas usen las bibliotecas de idiomas incorporadas en lugar de usar GSL, por ejemplo, que está en C.
Para rutinas muy genéricas, por ejemplo, generar muestras aleatorias a partir de distribuciones o rutinas numéricas básicas como la cuadratura de integrales, es fácil y común reutilizar alguna biblioteca. A medida que la funcionalidad que uno intenta implementar se vuelve más compleja, se vuelve exponencialmente más improbable que uno encuentre la función exacta que desea en otra biblioteca, e incluso si lo hace, podría pasar mucho tiempo buscando y finalmente adaptando la función como necesario (el estilo / diseño del código podría ser un problema, por ejemplo). Y como se discutió anteriormente, uno tiene acceso a solo un subconjunto de las bibliotecas disponibles. Por otro lado, implementar un algoritmo si es complejo y no es el foco principal puede ser desalentador, y por supuesto, uno tiene que lidiar con esos molestos problemas de velocidad.
Por lo tanto, esto se convierte en un problema de optimización en el análisis de costo / beneficio. Mi experiencia es que incluso para técnicas comparativamente estándar como MCMC, generalmente termino escribiendo mi propio código, porque se adapta mejor a cómo estoy diseñando el software en general.
Por supuesto, incluso si termina sin usar el código, es posible aprender del código de otras personas. Sin embargo, no sé con qué frecuencia los científicos realmente se molestan en hacer esto. Mi impresión es que leer el código de otras personas para aprender es más una cosa de ingeniero de software.
fuente
Pensando en mi curso de mecánica de segundo año, se me ocurre que parte de la razón por la que he implementado mis propias versiones de algoritmos conocidos es que me enseñaron a hacerlo de esa manera. No puedo pensar en un solo ejemplo en el que me enseñaron cómo interactuar y vincular en una biblioteca en mi educación física de pregrado. Tengo un buen recuerdo de ver por primera vez una lista de coordenadas de una pelota de golf giratoria, después de haber calculado la solución de las ecuaciones de Newton acopladas en FORTRAN. Hay una cierta emoción y satisfacción (incluso orgullo) que proviene de calcular cosas desde cero.
fuente
Creo que uno debería usar bibliotecas probadas tanto como sea posible. La mayoría de las personas no son expertos en informática numérica y probablemente no podrán implementar una solución tan correcta y cuidadosamente como lo que está disponible en bibliotecas bien probadas. Dicho esto, sin embargo, a veces ocurre que no hay bibliotecas disponibles que implementen la combinación de capacidades necesarias en una aplicación determinada. He visto que esto sucede en el área técnica en la que trabajo; los códigos existentes no resolvieron todos los casos, y alguien terminó implementando un solucionador desde cero que lo hizo.
fuente
El problema fundamental es a menudo con la interfaz entre la aplicación y la biblioteca. Un programador de aplicaciones tiene conocimiento sobre el problema que a menudo se pierde al pasar el problema (por ejemplo, como una matriz) a una biblioteca. Este conocimiento es tal que explotarlo más que compensa los beneficios de usar la biblioteca altamente optimizada. Como resultado, el programador de la aplicación "lanza" su propia implementación que explota el conocimiento.
Por lo tanto, una biblioteca realmente buena necesita que dicho conocimiento pase de la aplicación a la biblioteca, para que la biblioteca también pueda aprovecharlo.
fuente
Además de todas las cosas ya mencionadas anteriormente, repetiré mi respuesta de la pregunta "Fortran vs C ++": el activo más valioso que tiene un programador es su tiempo. Sí, las dependencias externas a menudo son incómodas. Pero pasar tiempo para volver a implementar, depurar y probar algoritmos que otros ya han implementado es casi siempre estúpido, y el resultado rara vez será tan bueno como el código escrito por expertos en un tema en particular. ¡Reutilice lo que otros han hecho!
fuente
El grupo con el que trabajo utiliza bibliotecas tanto como sea posible. Soy uno de los pocos programadores, y el resto de la gente comenzó a programar en el trabajo. Saben lo suficiente de sus propias limitaciones para saber dónde no deberían estar incursionando. IMSL es la biblioteca preferida. Cosas como GSL estarían prohibidas debido a restricciones de licencia, a pesar de que esta es una agencia federal y de todos modos regalamos nuestro software.
fuente
"La reutilización es principalmente un fenómeno social. Puedo usar el software de otra persona siempre que
"- B. Stroustrup, El lenguaje de programación C ++ 2 ed. (1991) p. 383.
fuente
Otros han dado varias buenas razones para usar bibliotecas y también para desarrollar sus propias rutinas.
A veces puede acelerar los cálculos para una aplicación específica porque sabe de antemano que nunca necesitará la amplia gama de valores que cubre la rutina de la biblioteca o la precisión que ofrecen esas rutinas.
Por supuesto, mucho depende de la aplicación particular y de cuántas veces se llamará a la rutina de la biblioteca. ¿Por qué llamaría a una rutina de biblioteca para las funciones de Bessel miles de millones de veces si solo necesita unas pocas cifras significativas para un pequeño rango de x, y alguna técnica más simple será suficiente para sus necesidades?
fuente
Es poco para agregar, tenemos que reutilizar el código, se trata de la sostenibilidad del código y la contribución a la sociedad, pero eso es todo lo anterior.
La razón por la que no reutilizamos el código es que si está comenzando a programar, es difícil entender el código de otros. Es particularmente difícil con C ++ avanzado, y también puedes hacer algunos trucos en C puro.
Muy a menudo al principio, uno comprende el método, pero no como está implementado en la biblioteca, o simplemente cómo usar la biblioteca con su interfaz genérica, control de errores y convenciones, muy a menudo documentada para programadores experimentados. Esto da la ilusión de que es mejor implementar un método estándar, como la factorización LU usted mismo. Además, los nuevos programadores subestiman el valor de las pruebas de código, la validación y la portabilidad para diferentes sistemas operativos. Entonces, al final la razón es la pereza, escribir un código propio parece una solución más rápida y fácil.
La realidad es que podemos aprender más usando y leyendo código que programando usted mismo desde cero.
La pereza me conduce la mayor parte del tiempo, creo que también la mayoría de las personas. Por la misma razón, algunos escriben código desde cero y otros usan bibliotecas existentes.
fuente
Los algoritmos de las bibliotecas proporcionan, en contraste con las implementaciones propias:
Todavía lo considero bueno cuando ingreso a un nuevo campo para implementar una versión de un algoritmo bien entendible por su cuenta. Me lleva mucho tiempo en total. Compré y leí libros, el llamado Press et al. Siempre leo mucha teoría antes y durante esas implementaciones. Y después de comprender los conceptos generales de un campo y experimentar las trampas en la práctica para mí, es hora de saltar a las mejores implementaciones de la biblioteca en todos los aspectos. Creo que se convertirá en un mejor usuario de la biblioteca si escribió un algoritmo "hello world" en el campo de las bibliotecas por su cuenta.
Si trabaja en un equipo más grande, puede que no sea su elección si su equipo usa una biblioteca específica o no. El equipo central podría tomar la decisión. Y puede haber una persona responsable del enlace de la biblioteca en su proyecto con sus propios planes de tiempo. Reescribiendo un algoritmo que puede hacer con su propia planificación del tiempo, sin depender de la decisión de otras personas.
Si está solo y desea distribuir, hay otro problema. Considero, además de muchos otros códigos fuente, el recurso más útil. Muchos a todos los informadores podrían estar de acuerdo aquí. En un campo aplicado fuera de la informática, podría ser necesario proporcionar un ejecutable precompilado en Windows. En Linux, puede configurar cosas relativamente fáciles por su cuenta en el caso de bibliotecas de uso de código abierto.
Reescribir un algoritmo por su cuenta le da libertad de licencia. Su proyecto podría no ser compatible con la licencia GPL de GSL, por ejemplo.
La licencia podría ser la única restricción que es independiente del punto de vista de los investigadores.
fuente