Eine konkrete Empfehlung für eine bestimmte Library werde ich nicht abgeben.
Aber ich habe schon in verschiedenen Zusammenhängen nach ähnlichen Libraries gesucht. Die genannten Anforderungen klingen teilweise recht vordergründig. Man stelle sich eine Matrix-Library vor, die wie folgt für sich wirbt:
Features of the CML (Crappy Matrix Library)
[ul]
[li]Very memory consuming (can only handle Matrices up to 13x17)[/li]> [li]Does not offer any matrix operations at all (yeah, NONE of them!)[/li]> [li]Very slow! (The latest version is 34% slower than the previous one!)[/li]> [/ul]
(Aber teilweise ist natürlich klar, was gemeint ist ;-))
Ein paar Gedanken dazu:
-
Große Matrizen. Da stellt sich natürlich die Frage: WIE groß? Und: Geht es um Dense oder Sparse Matrizen? Die meisten (außer den „einfachsten“) Libraries haben ja die explizite Unterscheidung zwischen Dense und Sparse Matrizen. Ganz grob kann man sagen: Sparse Matrizen brauchen weniger Speicher, sind aber langsamer (und bieten ggf. weniger (effiziente) Operationen an.
-
Die „üblichen“ Matrix-Operationen: Da kann man teilweise sehr weit gehen, in bezug auf die Frage, was „üblich“ ist. Mutliplikation, Transponieren, Invertieren? Joa. LU-Faktorisierung mit Cholesky-Preconditioner? Naja. Bequeme, effiziente, elementweise Operationen auf den Matrizen? Hm.
-
Performance. Auch da kann man sehr viel Aufwand reinstecken. Bei sowas wie Java Matrix Benchmark ist jemand schonmal recht weit gegangen. Aber die Abwägung muss da auch auf den Anwendungsfall bezogen sein. Das fängt an bei den VIELEN (!) Freiheitsgraden, die so ein Performancetest hat: Kleine vs. Große Matrizen? Dünnbesetzt vs. dichtbesetzt? Welche Operationen genau müssen besonders performant sein? Welche Prioritäten setzt man, in bezug auf den Trade-Off zwischen Performance, Einfachheit, Generalität, Flexibilität? Die Multiplikation zweiter („großer“) dichtbesetzter double-Matrizen wird man in Java kaum schneller machen können, als mit JCublas. Das soll aber keine Eigenwerbung sein: Der Aufwand, um diese Operation mit dieser Performance zu nutzen, ist vergleichsweise hoch, und die Flexibilität (oder allgemeiner: Der Erfüllungsgrad der anderen Punkte) ist gering bzw. schlicht NICHT vorhanden.
-
Zugriff auf Zeilen/Spalten: Das bieten „viele“ Libraries, mit unterschiedlichen Abstufungen. Wenn die Library auch nur einen Hauch Abstraktion hat, kann man sowas auch recht trivial selbst implementieren (wobei es, wenn es mit der jeweiligen Library „einfach“ möglich ist, es meistens auch schon eingebaut ist ;-))
-
Zeilen/Spalten hinzufügen/entfernen: Da wird es schon deutlich dünner. Man muss wohl damit rechnen, dass eine Library, die auf Algebra/BLAS Operationen ausgelegt ist, eine Matrix nicht als „rechteckige, über 2D indizierbare Liste“ ansieht, sondern wirklich als Matrix - und eine Matrix hat eine bestimmte Größe, und üblicherweise ist die nicht dynamisch…
-
Missing values darstellen: Da steckt im hervorgehobenen Wort eine Anforderung, die von fast KEINER Library angeboten wird: Die Darstellung. Im oben angedeuteten Sinn zielen die meisten Libraries eben darauf ab, eine Library für Mathematische Operationen zu sein. Etwas, womit nur gerechnet wird. Die Darstellung ist ein Thema, das dazu komplett orthogonal ist (sein kann/sein sollte…). Es GIBT natürlich libraries, wo ~„zusätzlich noch irgendwas für die Visualisierung“ angeboten wird. Aber je nachdem, wie das in den Anwendungskontext integriert sein soll, muss man sich da ggf. andere Optionen offen halten
-
Thread-safety: Abgesehen davon, dass bestimmte Operationen parallel ausgeführt werden, wird wohl praktisch KEINE Library „thread safe“ sein, in dem Sinne, dass um jeden furz-Setter ein dickes synchronized
gewickelt wird. Das hat einfach mit den „üblichen“ Anwendungsszenarien so einer Library nichts zu tun, bzw. würde ggf. „von außen“ sichergestellt werden müssen.
Allgemein ist die Spanne und der Raum der Optionen bei solchen Libraries SO gigantisch und SO abhängig vom jeweiligen Anwendungsfall, dass es sicher kein „Silver Bullet“ gibt. Bei einigen meiner Recherchen fand ich eine Sache bezeichnend - nämlich die gigantische Spanne zwischen
[ul]
[li]Der Klasse Matrix aus JAMA: „public class Matrix“, praktisch ein gewrappter 2D-double-Array[/li][li]Der nächsten Entsprechung dieser Klasse in UJMP: DefaultDenseDoubleMatrix2D, die von 7 Klassen erbt, und 77 (siebenundsiebzig!) interfaces implementiert[/li][/ul]
Das https://ujmp.org/ ist, wie man sich schon anhand dessen denken kann, engineered bis zum Anschlag - und, wie der Name schon suggeriert, zielt es auf Universalität ab. Das interessanteste daran fand ich, dass es die Möglichkeit bietet, über einen Plugin-Mechanismus Matrizen aus fast jeder anderen Matrix-Library transparent zu integrieren. („fast“ jeder - überraschenderweise scheint „jeigen“ gerade NICHT dabei zu sein ). Es bietet wohl auch ein Plugin für die Visualisierung, wie auch im Hintergrundbild der Homepage zu sehen ist. Aber wirklich „aktiv“ damit gearbeitet habe ich noch nicht, deswegen soll das keine Emfehlung für die Library selbst sein, sondern nur die Empfehlung, da mal ein Auge drauf zu werfen.
(Aber nur nebenbei: Selbst diese Library bietet anscheinend nicht die Möglichkeit, Zeilen/Spalten zu einer Matrix hinzuzufügen. Das ist einfach zu unüblich. Die Option, sich dafür eine eigene Datenstruktur zu basteln, und um diese Struktur dann ein passendes Interface zu wickeln, sollte es aber bei allen Libraries geben, die „die zentrale ‚Matrix‘“ nicht als Klasse, sondern als Interface definiert haben)