Zahlreiche numerische Algorithmen (Integration, Differenzierung, Interpolation, Sonderfunktionen usw.) sind in wissenschaftlichen Berechnungsbibliotheken wie GSL verfügbar . Aber ich sehe oft Code mit "handgerollten" Implementierungen dieser Funktionen. Ist es bei kleinen Programmen, die nicht unbedingt für die öffentliche Verbreitung bestimmt sind, unter Computerwissenschaftlern üblich, nur selbst numerische Algorithmen zu implementieren (dh von einer Website, numerischen Rezepten oder ähnlichem zu kopieren oder zu transkribieren), wenn Sie diese benötigen? Wenn ja, gibt es einen bestimmten Grund, die Verlinkung mit so etwas wie GSL zu vermeiden , oder ist es eher "Tradition" als irgendetwas anderes?
Ich frage, weil ich ein großer Fan der Wiederverwendung von Code bin , was nahelegt, dass ich versuchen sollte, vorhandene Implementierungen zu verwenden, wenn dies möglich ist. Aber ich bin neugierig, ob es Gründe gibt, warum dieses Prinzip beim wissenschaftlichen Rechnen weniger wert ist als beim allgemeinen Programmieren.
Vergessen zu erwähnen: Ich frage speziell nach C und C ++, im Gegensatz zu Sprachen wie Python, bei denen die Verwendung einer Bibliothek einen klaren Vorteil (Geschwindigkeit der Ausführung) hat.
Antworten:
Früher habe ich alles selbst implementiert, aber in letzter Zeit habe ich viel mehr Bibliotheken verwendet. Ich denke, es gibt einige sehr wichtige Vorteile der Verwendung einer Bibliothek, die über die Frage hinausgehen, ob Sie selbst eine Routine schreiben müssen oder nicht. Wenn Sie eine Bibliothek verwenden, erhalten Sie
Im letzten Punkt oben denke ich an große Bibliotheken wie Trilinos oder PETSc . Dies kann ich mit einigen konkreten persönlichen Beispielen in der Entwicklung von PyClaw untermauern . Obwohl es einfach gewesen wäre, Clawpack mit MPI-Aufrufen zu parallelisieren , haben wir uns für PETSc entschieden. Auf diese Weise konnten wir den Paralle-Code im Paket auf weniger als 300 Zeilen Python beschränken. Durch das Versetzen unserer Daten in das PETSc-Format erhielten wir jedoch sofort Zugriff auf die impliziten Löser von PETSc, was die aktuelle Arbeit an einem impliziten Löser in PyClaw ermöglichte. Als zweites Beispiel enthielt PyClaw anfänglich eine WENO-Rekonstruktion fünfter Ordnung mit Handcode, aber wir entschieden uns schließlich, uns auf PyWENO zu verlassenPaket dafür. Dies war ein großer Vorteil, da PyWENO automatisch WENO-Routinen in beliebiger Reihenfolge in mehreren Sprachen generieren kann.
Wenn Sie Bibliotheken verwenden, können Sie einen Beitrag leisten, indem Sie Verbesserungen entwickeln oder Fehler finden, von denen viele andere profitieren, während das Debuggen oder Verbessern Ihres eigenen Codes nur Ihnen zugute kommt.
quelle
Das Verknüpfen mit einer Bibliotheksfunktion ist mit einem erheblichen Programmieraufwand verbunden, insbesondere wenn diese Bibliothek für den Programmierer neu ist. Es ist oft einfacher, einfache Algorithmen neu zu schreiben, als die Besonderheiten einer bestimmten Bibliothek herauszufinden. Wenn die Algorithmen komplexer werden, ändert sich dieses Verhalten.
Python konnte diesen Overhead mit Tools wie pip / easy_install und einer einheitlichen Datenstrukturschnittstelle (dh, jede Bibliothek scheint ein numpy-Array zu nehmen und zu produzieren) hervorragend reduzieren.
quelle
Eines der Projekte, an denen ich gerade beteiligt bin, ist das Schreiben eines flexiblen Simulations- und Analysepakets für eine Klasse von Detektoren der Teilchenphysik. Eines der Ziele dieses Projekts ist es, die Codebasis bereitzustellen, die in den kommenden Jahrzehnten in diesen Dingen verwendet werden soll.
Zu diesem Zeitpunkt haben wir bereits zwei Dutzend Abhängigkeiten, was den Erstellungsprozess zu einem solchen Albtraum macht, dass er ein separates Projekt ausgelöst hat, das vom Fermilab-Rechenzentrum aus verwaltet wird, um eine zuverlässige Toolkette bereitzustellen.
Stellen Sie sich nun vor, Sie brauchen ein Tool, das nicht in dieser Toolkette enthalten ist (mir ist es erst letzten Monat passiert). Sie haben drei Möglichkeiten
Es ist sehr einfach zu wählen (1). Vielleicht zu einfach.
quelle
Ich denke, es ist ziemlich üblich, dass einige Algorithmen eher reimplementiert werden als andere.
Es gibt einen kniffligen Kompromiss zwischen der lästigen Installation einer Bibliothek, der Schwierigkeit, den Algorithmus selbst zu implementieren, der Schwierigkeit, ihn zu optimieren und der Anpassung der Bibliothek an Ihre Anforderungen. Manchmal ist die Verwendung einer Bibliothek einfach zu viel: Ich habe in einem meiner Programme den langsamen Halbierungsalgorithmus verwendet, weil ich ihn nur ein paar Mal aufgerufen habe und deshalb keine Bibliothek hinzufügen wollte.
Ist es für Sie einfach, eine gut optimierte Version zu schreiben? Wenn ja, ist es vielleicht besser für Sie. Sie bekommen genau das, was Sie brauchen und sind nicht auf die Arbeit anderer angewiesen. Aber natürlich müssen Sie wirklich wissen, was Sie tun: Selbst einfache Algorithmen können schwierig zu implementieren sein.
Ich wäre gespannt auf eine Studie dazu, aber aus meiner voreingenommenen Perspektive verwenden Wissenschaftler häufig Bibliotheken für lineare Algebra und Zufallszahlengeneratoren, wobei der größte Teil des verbleibenden Codes hausgemacht ist.
quelle
Ich denke, dass die Implementierung eines Algorithmus anstelle der Verwendung einer Bibliothek manchmal zu einem besseren Verständnis und einer besseren Kontrolle des Modells führen kann. Wenn ich ein Programm für wissenschaftliche Berechnungen programmiere, ist es für mich wichtig zu verstehen, was ich tue. Die Implementierung der wichtigen Algorithmen hilft mir, das Problem besser zu kennen und besser zu kontrollieren.
Andererseits ist es manchmal keine einfache Aufgabe, eine Bibliothek auszuwählen, die zum Abrufen einer Lösung benötigt wird. Es ist daher besser, nach bereits implementierten Algorithmen zu suchen, wenn Sie sicher sind, was Sie erreichen möchten und warum Sie es möchten.
Wenn die Algorithmen komplex sind, haben Sie durch die manuelle Codierung die Möglichkeit, die Leistung / Qualität der Lösung mithilfe aufgabenspezifischer Funktionen zu verbessern. Und manchmal ist es notwendig, den Algorithmus ein wenig zu ändern. Dies ist einfacher, wenn Sie den von Ihnen geschriebenen Code kennen und ihn nach Ihren Wünschen bearbeiten können.
quelle
Eine Antwort ist, dass es so viele geringfügige Variationen des numerischen Codes gibt, dass es wirklich schwierig ist, dies in einer Bibliothek zu kapseln. Nehmen Sie dies im Vergleich zu Web-Software, die oft einfach zu installieren ist und eine klare Reihe von Ein- und Ausgängen hat. Ich denke, häufiger greifen Leute nach einem Framework oder einer großen Bibliothek, die wie ein Framework fungiert (Trilinos / PETSc), und nutzen dieses Ökosystem, um die Vorteile der Verwendung von Community-Codes zu nutzen.
quelle
Bevor Sie entscheiden, ob Sie Bibliotheken verwenden möchten oder nicht, sollten Sie auch herausfinden, inwieweit die Verwendung einer Bibliothek Ihrem Code hilft. Wenn Sie eine gut optimierte Bibliothek für einen wichtigen Rechenkern verwenden, ist dies wahrscheinlich weitaus effizienter als der Versuch, eine eigene Bibliothek zu schreiben.
Wenn Sie jedoch eine spezielle Routine schreiben, die während der Ausführung eines Programms nur einmal aufgerufen wird, lohnt es sich möglicherweise nicht, den Code an das für eine Bibliothek erforderliche Framework anzupassen.
(Eine weitere Überlegung: Wie viel Umbau müssen Sie tun, um die Bibliothek zu nutzen? Sofern die für die Korrektur des Codes aufgewendeten Arbeitsstunden nicht durch entsprechende Effizienz- oder Genauigkeitsgewinne ausgeglichen werden, ist dies möglicherweise nicht der Fall Auf lange Sicht lohnt sich das. Idealerweise planen Sie dies jedoch, wenn Sie zunächst Datenstrukturen und Algorithmen entwerfen, damit der "Fluss" der Bibliothek von Grund auf berücksichtigt wird.)
quelle
Meine 2 Cent.
Ich denke, es ist einfacher, allgemein darüber zu schreiben, als nur über C / C ++. Erstens werden Bibliotheken in Sprachen wie Python nicht unbedingt verwendet, um einen Geschwindigkeitsvorteil zu erzielen, auch wenn dies eine Konsequenz ist. Ich denke, @David hat die Gründe ziemlich gut dargelegt .
Von oben betrachtet, bestimmt die Sprachimplementierung in gewissem Maße, auf welche Bibliotheken Sie zugreifen können. Zu den in der Computerwissenschaft am häufigsten verwendeten Sprachen gehören C, C ++, Python, Perl, Java, Fortran und R. Weniger häufig verwendete Beispiele sind Ocaml und Common Lisp. Da die meisten dieser Sprachen in C geschrieben sind, haben sie eine natürliche Fremdfunktionsschnittstelle zu C. Es ist jedoch nicht so einfach, beispielsweise eine Perl-Bibliothek aus Python oder umgekehrt aufzurufen. In der Praxis neigen die Leute also dazu, entweder
Verwenden Sie eine Bibliothek, die in ihrer Implementierungssprache geschrieben ist, normalerweise als Teil der Standardbibliotheken oder auf andere Weise allgemein verfügbar
Rufen Sie eine C / C ++ - Bibliothek über die Sprachen FFI auf. Dies setzt voraus, dass ein Wrapper noch nicht existiert, da er sonst nicht leicht von (1) zu unterscheiden ist.
(2) ist normalerweise schwieriger, da Sie die C / C ++ - Funktion selbst umbrechen müssen. Außerdem müssen Sie entweder die Bibliothek bündeln oder eine zusätzliche Abhängigkeit hinzufügen. Aus diesem Grund verwenden Benutzer eher die integrierten Sprachbibliotheken als beispielsweise GSL (in C).
Bei sehr generischen Routinen, z. B. der Erzeugung von Zufallsstichproben aus Verteilungen oder grundlegenden numerischen Routinen wie der Quadratur von Integralen, ist es einfach und üblich, einige Bibliotheken wiederzuverwenden. Da die Funktionalität, die Sie implementieren möchten, immer komplexer wird, wird es exponentiell unwahrscheinlicher, dass Sie genau die gewünschte Funktion in einer anderen Bibliothek finden, und selbst wenn Sie dies tun, können Sie viel Zeit damit verbringen, die Funktion zu suchen und schließlich anzupassen notwendig (der Code-Stil / Design könnte zum Beispiel ein Problem sein). Und wie oben diskutiert, hat man Zugriff auf nur eine Teilmenge der Bibliotheken da draußen. Andererseits kann es entmutigend sein, einen Algorithmus selbst zu implementieren, wenn er komplex ist und nicht das Hauptaugenmerk liegt, und natürlich muss man sich mit diesen lästigen Geschwindigkeitsproblemen befassen.
Dies wird zu einem Optimierungsproblem bei der Kosten-Nutzen-Analyse. Ich habe die Erfahrung gemacht, dass ich selbst für vergleichsweise Standardtechniken wie MCMC in der Regel meinen eigenen Code schreibe, weil er besser zu der Art und Weise passt, wie ich die gesamte Software entwerfe.
Selbst wenn Sie den Code am Ende nicht verwenden, können Sie natürlich auch aus dem Code anderer lernen. Ich weiß allerdings nicht, wie oft sich Wissenschaftler tatsächlich die Mühe machen, dies zu tun. Mein Eindruck ist, dass das Lesen des Codes anderer Leute eher eine Sache des Software-Ingenieurs ist.
quelle
Wenn ich an meinen Mechanikkurs im zweiten Jahr zurückdenke, fällt mir ein, dass ein Teil der Gründe, warum ich meine eigenen Versionen bekannter Algorithmen implementiert habe, darin besteht, dass mir beigebracht wurde, dies auf diese Weise zu tun. Ich kann mir kein einziges Beispiel vorstellen, in dem mir beigebracht wurde, wie man in meiner Grundausbildung in Physik eine Schnittstelle zu einer Bibliothek herstellt und diese damit verbindet. Ich kann mich gut daran erinnern, dass ich zum ersten Mal eine Liste der Koordinaten eines sich drehenden Golfballs gesehen habe, nachdem ich die Lösung der gekoppelten Newton-Gleichungen in FORTRAN selbst berechnet habe. Es gibt einen gewissen Nervenkitzel und eine gewisse Befriedigung (sogar einen gewissen Stolz), wenn Dinge von Grund auf neu berechnet werden.
quelle
Ich denke, man sollte so oft wie möglich getestete Bibliotheken verwenden. Die meisten Leute sind keine Experten für numerisches Rechnen und werden wahrscheinlich nicht in der Lage sein, eine Lösung so korrekt und sorgfältig zu implementieren, wie es in gut getesteten Bibliotheken verfügbar ist. Gelegentlich gibt es jedoch keine verfügbaren Bibliotheken, die die in einer bestimmten Anwendung erforderliche Kombination von Funktionen implementieren. Ich habe dies in dem technischen Bereich gesehen, in dem ich arbeite. Bestehende Codes lösten nicht alle Fälle, und schließlich implementierte jemand einen Solver von Grund auf neu.
quelle
Das grundlegende Problem liegt häufig in der Schnittstelle zwischen der Anwendung und der Bibliothek. Ein Anwendungsprogrammierer hat Kenntnisse über das Problem, die häufig verloren gehen, wenn das Problem (beispielsweise als Matrix) an eine Bibliothek übergeben wird. Dieses Wissen ist so beschaffen, dass es die Vorteile der Verwendung der hochoptimierten Bibliothek mehr als wettmacht. Infolgedessen "rollt" der Anwendungsprogrammierer seine / ihre eigene Implementierung, die das Wissen ausnutzt.
Daher muss eine wirklich gute Bibliothek dieses Wissen von der Anwendung an die Bibliothek weitergeben, damit auch die Bibliothek es nutzen kann.
quelle
Zusätzlich zu all dem, was oben bereits gesagt wurde, möchte ich meine Antwort auf die Frage "Fortran vs C ++" wiederholen: Das wertvollste Kapital, das eine Programmiererin hat, ist ihre Zeit. Ja, externe Abhängigkeiten sind oft umständlich. Es ist jedoch fast immer dumm, Zeit für die Neuimplementierung, das Debuggen und Testen von Algorithmen zu investieren, die bereits von anderen implementiert wurden, und das Ergebnis ist selten so gut wie Code, der von Experten zu einem bestimmten Thema geschrieben wurde. Verwenden Sie das, was andere getan haben, wieder!
quelle
Die Gruppe, mit der ich zusammenarbeite, verwendet so oft wie möglich Bibliotheken. Ich bin einer der wenigen Programmierer, und der Rest der Leute hat das Programmieren bei der Arbeit aufgenommen. Sie wissen genug über ihre eigenen Grenzen, um zu wissen, wo sie sich nicht austoben sollten. IMSL ist die bevorzugte Bibliothek. Sachen wie GSL wären aus lizenzrechtlichen Gründen verboten, auch wenn dies eine Bundesbehörde ist und wir unsere Software trotzdem weitergeben.
quelle
"Die Wiederverwendung ist in erster Linie ein soziales Phänomen. Ich kann die Software eines anderen Benutzers verwenden, sofern dies der Fall ist
"- B. Stroustrup, The C ++ Programming Language 2 ed. (1991) S. 383.
quelle
Andere haben gute Gründe angegeben, Bibliotheken zu verwenden und eigene Routinen zu erstellen.
Manchmal können Sie die Berechnungen für eine bestimmte Anwendung beschleunigen, weil Sie im Voraus wissen, dass Sie niemals den großen Wertebereich, den die Bibliotheksroutine abdeckt, oder die Genauigkeit benötigen, die diese Routinen liefern.
Natürlich hängt vieles von der jeweiligen Anwendung ab und davon, wie oft die Bibliotheksroutine aufgerufen wird. Warum würden Sie eine Bibliotheksroutine für Bessel-Funktionen milliardenfach aufrufen, wenn Sie nur einige signifikante Zahlen für einen kleinen Bereich von x benötigen und eine einfachere Technik für Ihre Anforderungen ausreicht?
quelle
Ist wenig hinzuzufügen, wir müssen Code wiederverwenden, es geht um Code-Nachhaltigkeit und einen Beitrag zur Gesellschaft, aber das ist alles oben.
Der Grund, warum wir Code nicht wiederverwenden, ist, dass es schwierig ist, anderen Code zu verstehen, wenn Sie mit dem Programmieren beginnen. Bei fortgeschrittenem C ++ ist dies besonders schwierig, und Sie können einige Tricks auch in reinem C ausführen.
Sehr oft versteht man zu Beginn die Methode, aber nicht, wie sie in der Bibliothek implementiert ist, oder einfach, wie man die Bibliothek mit ihrer generischen Schnittstelle, Fehlerkontrolle und Konventionen verwendet, die für erfahrene Programmierer sehr oft, wenn überhaupt, dokumentiert wird. Dies gibt die Illusion, dass es besser ist, eine Standardmethode wie die LU-Faktorisierung selbst zu implementieren. Darüber hinaus unterschätzen neue Programmierer den Wert von Code-Tests, Validierung und Portabilität für verschiedene Betriebssysteme. Der Grund dafür ist also Faulheit. Das Schreiben von eigenem Code scheint eine schnellere und einfachere Lösung zu sein.
Die Realität ist, dass wir durch das Verwenden und Lesen von Code mehr lernen können, als durch das Programmieren von Grund auf.
Faulheit treibt mich die meiste Zeit an, ich denke auch die Mehrheit der Menschen. Aus dem gleichen Grund schreiben einige Code von Grund auf neu und andere verwenden vorhandene Bibliotheken.
quelle
Bibliotheksalgorithmen bieten im Gegensatz zu eigenen Implementierungen:
Ich halte es immer noch für gut, wenn Sie ein neues Feld eingeben, um eine Version eines gut verständlichen Algorithmus selbst zu implementieren. Insgesamt nehme ich mir viel Zeit. Ich kaufte und las Bücher, die genannten Press et al. Vor und während dieser Implementierungen habe ich immer viel Theorie gelesen. Und nachdem ich die allgemeinen Konzepte eines Feldes verstanden und die Fallen in der Praxis erlebt habe, ist es an der Zeit, zu den in allen Aspekten besseren Bibliotheksimplementierungen zu springen. Ich denke, Sie werden ein besserer Benutzer der Bibliothek, wenn Sie selbst einen "Hallo Welt" -Algorithmus im Bibliotheksbereich schreiben.
Wenn Sie in einem größeren Team arbeiten, ist es möglicherweise nicht Ihre eigene Wahl, ob Ihr Team eine bestimmte Bibliothek verwendet oder nicht. Das Kernteam könnte die Entscheidung treffen. Und es könnte eine Person geben, die für die Bindung der Bibliothek in Ihrem Projekt mit eigenen Zeitplänen verantwortlich ist. Umschreiben eines Algorithmus, den Sie mit Ihrer eigenen Zeitplanung durchführen können, ohne sich auf die Entscheidung anderer Personen verlassen zu müssen.
Wenn Sie alleine sind und gerne vertreiben, gibt es ein anderes Problem. Ich halte so gut wie viele andere Quellcodes für die nützlichste Ressource. Viele an alle Informatiker könnten hier zustimmen. In einem Anwendungsbereich außerhalb der Informatik kann es erforderlich sein, ein vorkompiliertes Programm für Windows bereitzustellen. Unter Linux können Sie bei Open Source-Verwendungsbibliotheken die Dinge relativ einfach selbst einrichten.
Das eigenständige Umschreiben eines Algorithmus gibt Ihnen die Freiheit, die Lizenz zu behalten. Ihr Projekt unterstützt beispielsweise möglicherweise nicht die GPL- Lizenz von GSL .
Die Lizenz könnte die einzige Einschränkung sein, die vom Standpunkt des Forschers unabhängig ist.
quelle