Re: [boost] Boost Digest, Vol 7345, Issue 1
Hi Artyom, Thank you for you for noticing the proposal and the feedback.
It can be excellent to have something like standard MD arrays like numpy is today for python, but...
yes, this is one of the goals.
1. You haven't mentioned even once OpenCV which today is the de-facto standard for numerical computing in today's C++ world.
From the introduction "The library's primary concern is with the storage and logic structure of data; it doesn't make algebraic or geometric assumptions about the arrays and
I do scientific computing with large arrays, and nobody uses OpenCV. It would be fair if you had said that it is the de facto standard for image processing, which I don't do. Second, Multi is not a numerical library specifically; it is about the logic and semantics of multidimensional arrays and containers, regardless of the element type. Having said that, the library should still be very performant with numerical data, and for that, I delegate that responsibility to the algorithms it uses behind the scenes, which are very customizable. Unfortunately, people read "arrays" immediately jump to "numerics" and "linear algebra". their elements. (It is still a good building block for implementing mathematical algorithms, such as representing algebraic dense matrices in the 2D case.) In this sense, it is instead a building block to implement algorithms to represent mathematical operations, specifically on numeric data."
While it isn't perfect - it actually has similar features in terms of array layout - and what is more important it has a library of high performance algorithms to process the data. You must talk at least about interoperability between cv::Mat and this library
Multi is not an algorithms library, but it carefully plays with existing algorithms and facilitates as much as possible to interface with many numerical libraries.
2. While actual ndarry handling is nice, it is basically a tip of an iceberg. You need a decent set of high performance algo combined with it.
There is a clear separation of concerns here. The Multi library deals with the data structure, it uses when it needs to fulfill its semantics, the best *existing* algorithms it can in awareness of the datastructure. The Multi library doesn't provide algorithms, it uses the algorithms that are provided to it via different mechanisms.
Looks like there is a basic BLAS but the typical library has way-way more to make it useful.
This is an add-on that is separate from the main library. I cannot even guarantee that it will ship with the proposed version of the library. What do you mean by the "typical library" in "the typical library has way-way more to make it useful"? I agree, promising all linear algebra is infinite work, like reimplenting MATLAB or Mathematica, but BLAS has a finite number of functions. The philosophy of the BLAS-adaptor in particular (again, an optional component) is to interface to what BLAS offers and not more. It is more of a model how to interface a legacy library using the features of Multi.
I looked over the code and didn't find include to cblas... Did I miss something? Also I see request to link cblas/openblas or so.
Yes, you missed that depending on cblas would tie it the application to cblas, not all BLAS implementations can be used through cblas. BLAS is uses through the ABI directly. (basically I have my own version of the cblas header as an implementation detail). Also the BLAS interface is the same for cuBLAS, which is another story.
I did breef look into implementation and it seems to be lacking of vectorization (use of intrinsics/vector operators) or have I missed?
You missed that this is a generic, not specifically numerical, library. The other thing to take into account is that vectorization/parallelization is still provided by the external algorithms the library uses internally. For example, then dealing with GPU or OpenMP arrays, the library uses thrust algorithms if they are available, which are parallel. vectorization is use by passing execution policies, or whatever mechanism the underlying algorithms use as long as they conform to a certain syntax. (there are some commits coming regarding the passing of execution policies Remember that I don't use many algorithms internally, only those that are necessary to implement the semantics of the array types, assignment, move assignment, construction and destruction. The rest of the operations generate views mostly, so they don't involve computation or algorithms. For the rest, as a user, you have to use algorithms, and I can help if you find that algorithms do not perform as you expect.
3. Finally I do want to see comparison with stuff like OpenCV, Eigen and even uBlas (I know it isn't good)
Multi is for multidimensional arrays, not specifically 2D numerical arrays (i.e. matrices). I would be interested in improving the code if someone claims that operations in these libraries are better performant. I wouldn't want the documentation to be a comparison with so many libraries to which there is just very partial overlap. Specially I don't like to compare with frameworks that lock you in into using their own facilities. I consider that Eigen, OpenCV, Kokkos, PETSc are frameworks. Eigen is listed in one column comparing to other libraries. https://gitlab.com/correaa/boost-multi#appendix-comparison-to-other-array-li... I don't fill confident adding an OpenCV column because I don't have experience with it, but feel free to help me adding a library and answering the points of each row in the comparison table. 4. If you do implement many high performance algorithms this library by any
means shouldn't be header only.
I don't implement any high performance algorithms here, I just give the possibility to interface with them and use them internally when needed to fulfill the semantics of a container.
What is not clear to me is why should I use one over some existing solution like OpenCV?
- Because sometimes your elements are not numerical types. - Because sometimes you want to specify your element types as template parameters not as OpenCV encoded types. - Because sometimes you want arbitrary dimensionality (e.g. 2D, 3D, 6D) to be compile-time. - Because sometimes you want to apply generic algorithms to your arrays (STL, std::sort, std::rotate, std::ranges, boost::algorithms, serialization) - Because sometimes you want to implement function that are oblivious to the actual dimension or your array (e.g. simultaneously view a 3D array of elements as a 2D array of something, for abstraction). - Because sometimes you want to control allocations, use fancy pointers, parameterized memory strategies, polymorphic allocators, - Because sometimes you want precise value semantics - Because sometimes you want to give guarantees in the presence of exceptions (the library doesn't throw exceptions, to be clear). - Because sometimes you want to work with subblocks of an array in the same way to need you work with the whole array. Thanks, Alfredo
1. You haven't mentioned even once OpenCV which today is the de-facto
standard for numerical computing in today's C++ world.
I do scientific computing with large arrays, and nobody uses OpenCV. It would be fair if you had said that it is the de facto standard for image processing, which I don't do.
Ok... if you haven't used does not mean that it isn't very common computing library that many developers/designers go by default.
Second, Multi is not a numerical library specifically; it is about the logic and semantics of multidimensional arrays and containers, regardless of the element type. ...
See, this is exactly the problem. Why would I need something like that if I need to go to all the 3rd party libraries to actually use one efficiently? cv::Mat is numpy like NDArray with strides, windows, offsets (yes it supports more than two dimensions). I myself used/written several Tensor like objects and used (pytorch C++ tensor, dlprimitives and other objects). It is nothing new, by all means it is the easiest part of any numerical library.
2. While actual ndarry handling is nice, it is basically a tip of an iceberg. You need a decent set of high performance algo combined with it.
There is a clear separation of concerns here. The Multi library deals with the data structure, it uses when it needs to fulfill its semantics, the best *existing* algorithms it can in awareness of the datastructure. The Multi library doesn't provide algorithms, it uses the algorithms that are provided to it via different mechanisms.
But if you don't provide algorithms, maybe I'd better take a library/framework that does. There are plenty of numpy-like arrays around. Usually they are called tensors...
I agree, promising all linear algebra is infinite work, like reimplenting MATLAB or Mathematica, but BLAS has a finite number of functions. The philosophy of the BLAS-adaptor in particular (again, an optional component) is to interface to what BLAS offers and not more. It is more of a model how to interface a legacy library using the features of Multi.
But that is exactly what make opencv useful and multi-array like a fasade with emptiness behind.
I looked over the code and didn't find include to cblas... Did I miss something? Also I see request to link cblas/openblas or so.
Yes, you missed that depending on cblas would tie it the application to cblas, not all BLAS implementations can be used through cblas. BLAS is uses through the ABI directly. (basically I have my own version of the cblas header as an implementation detail).
I see, it is a questionable decision, but Ok.
I did breef look into implementation and it seems to be lacking of vectorization (use of intrinsics/vector operators) or have I missed?
You missed that this is a generic, not specifically numerical, library.
But, you making numpy-like library... otherwise you wouldn't be interfacing cblas. See, if you have been talking about multi-array as advanced std::vector of generic objects... Ok - but you don't you direct it to the numeric computations.
The other thing to take into account is that vectorization/parallelization is still provided by the external algorithms the library uses internally. For example, then dealing with GPU or OpenMP arrays, the library uses thrust algorithms if they are available, which are parallel.
Just for the record there are two levels of parallelization on CPU level: 1 thread based parallelization, 2nd SIMD level parallelization like SSE/AVX2/Neon - where you load vectors of 16, 32 bytes of data and process them together in a single instruction. These can increase the performance significantly. Compilers aren't always useful in this situation because of data dependencies that only the author can know.
3. Finally I do want to see comparison with stuff like OpenCV, Eigen and even uBlas (I know it isn't good)
Multi is for multidimensional arrays, not specifically 2D numerical arrays (i.e. matrices).
OpenCV isn't 2d only. It support n-D tensors with views.
I consider that Eigen, OpenCV, Kokkos, PETSc are frameworks.
It reminds me of a comparison of Boost.Beast and a full scale framework like CppCMS. When I reviewed beast it was clear that it does not do 10% of what is expected from something to make an actually useful web application. While it is nice to have an abstraction - if so either keep it basic or go full way - you are stuck somewhere in between std::vector ++ and something like OpenCV.
I don't fill confident adding an OpenCV column because I don't have experience with it, but feel free to help me adding a library and answering the points of each row in the comparison table.
I suggest getting some experience with OpenCV. It is a very good library that already implements what you have (also in a different way) It ain't perfect by any means. But it works, well debugged, understood and is a widely available library that does the job.
What is not clear to me is why should I use one over some existing solution like OpenCV?
- Because sometimes your elements are not numerical types.
Yeahhh... don't buy it. Sorry :-)
- Because sometimes you want to specify your element types as template parameters not as OpenCV encoded types.
To make your code compilation slower and more horrible? Actually OpenCV supports templated accessors.
- Because sometimes you want arbitrary dimensionality (e.g. 2D, 3D, 6D) to be compile-time.
And why it isn't possible with OpenCV
- Because sometimes you want to apply generic algorithms to your arrays (STL, std::sort, std::rotate, std::ranges, boost::algorithms, serialization)
Yeah... good luck with that in numerical context. But Ok. In OpenCV you can just get several pointers and work with them
- Because sometimes you want to implement function that are oblivious to the actual dimension or your array (e.g. simultaneously view a 3D array of elements as a 2D array of something, for abstraction). - Because sometimes you want to control allocations, use fancy pointers, parameterized memory strategies, polymorphic allocators,
OpenCV support custom allocations (actually something I exactly use right now to monitor memory consumption) Once again - be careful what you wish for. Templated allocators are huge headache to work with in comparison to run-time ones (in real - non fancy template world that Boost Loves)
- Because sometimes you want precise value semantics
I'm not sure it is a great idea for huge arrays/matrices. Virtually ALL tensor libraries have reference semantics for a very good reason.
- Because sometimes you want to work with subblocks of an array in the same way to need you work with the whole array.
And this is exactly what view is for... And this is common for any tensor library.
- Because sometimes you want to give guarantees in the presence of exceptions (the library doesn't throw exceptions, to be clear).
Ok this is one of the points I want to discuss here in terms of design, exceptions and broadcasting. Lets take an example (numpy - but same works for torch::Tensor) a=np.ones(5,10) b=np.ones(2,5,1) c=a+b It would perform broadcasting to Shape = (2,5,10) - automatically. How it can be done - you broadcast shapes of a to 2,5,10 using strides (0,10,1) and broadast b to same shape using strides (5,1,0) (I hope I have not mistaken in calcs) Then you can run easily on shape 2,5,10 and do all calculations, fetching etc. Looking into your broadcasting docs - left me with the impression it does not support anything like this. I read this:
First, broadcasted arrays are infinite in the broadcasted dimension; iteration will never reach the end position, and calling `.size()` is undefined behavior.
Why? You certainly can iterate over broadcasted dimension... Also how do you handle incompatible broadcasting without exception - for example if b in the example above was of shape (2,5,3) and not (2,5,1) Exceptions are useful. And claiming that you don't throw ones means you don't use new...
Thanks, Alfredo
Regards, I highly doubt the practicality of the library in the current form. While generic multi-array can be nice to have, but actually it is stuck at being little bit more that MultiArray but too far even from basic numpy. My $0.02 Artyom
On Sat, Sep 21, 2024, at 7:10 PM, Artyom Beilis via Boost wrote:
See, this is exactly the problem. Why would I need something like that if I need to go to all the 3rd party libraries to actually use one efficiently?
Can you give arguments why "I don't see why I need this" is an argument against a library existing?
But if you don't provide algorithms, maybe I'd better take a library/framework that does. Perhaps.
But, you making numpy-like library... otherwise you wouldn't be interfacing cblas.
A clear case of diyd/diyd ("Damned If You Do, Damned If You Don't"). Of all the features you're missing here you decry "At least show ways to interoperate with existing thirdparty libraries". Now, they went and did that (if I'm not mistaken, clearly marked as an extension that might not even be part of the proposed library), and you decry that. There's no winning.
It [OpenCV] ain't perfect by any means. But it works, well debugged, understood and is a widely available library that does the job.
It's also a pretty heavy dependency, especially if you didn't need all the other stuff, and appears to be an example of an intrusive framework (for good reason, IFF you need the rest)
To make your code compilation slower and more horrible?
This seems a weird argument to me. The year is 2024. Perhaps you need to update your tools.
Yeah... good luck with that in numerical context. But Ok. In OpenCV you can just get several pointers and work with them
And enjoy bugs without guard-rails. I've implemented serialization on both Cv* and Eigen types, and remember getting it very very subtly wrong without noticing for a long while.
Exceptions are useful. And claiming that you don't throw ones means you don't use new...
Many things don't require allocation. Meanwhile `new(std::nothrow)` has existed since c++11.
Regards, I highly doubt the practicality of the library in the current form. While generic multi-array can be nice to have, but actually it is stuck at being little bit more that MultiArray [...]
These two sentences are your review! I cannot disagree here, and you have been right in voicing your concern...
[...] but too far even from basic numpy.
... but this seems to cross over to normative apples/oranges comparison. I could say your review is too far even from basic poetry with equal merit.
My $0.02
Artyom
I have no real clue here, I'm here to learn from both your viewpoints. However mdarray/mdspan facilities are an oft recurring thing - including in the standard - so I'm tempted to think there is demand. I'm reminded of the once-common schism between game-dev C++ and non-game-dev C++: for a long time useful things were blocked from C++'s evolution because game-devs didn't see the need for them. I'm pretty happy the community grew past that (even though it gave us some wind-eggs like std::async and possibly other stunted features in the future) Cheers, Seth
On 22/09/2024 16:13, Seth via Boost wrote:
On Sat, Sep 21, 2024, at 7:10 PM, Artyom Beilis via Boost wrote:
See, this is exactly the problem. Why would I need something like that if I need to go to all the 3rd party libraries to actually use one efficiently? Can you give arguments why "I don't see why I need this" is an argument against a library existing?
But if you don't provide algorithms, maybe I'd better take a library/framework that does. Perhaps.
But, you making numpy-like library... otherwise you wouldn't be interfacing cblas. A clear case of diyd/diyd ("Damned If You Do, Damned If You Don't"). Of all the features you're missing here you decry "At least show ways to interoperate with existing thirdparty libraries". Now, they went and did that (if I'm not mistaken, clearly marked as an extension that might not even be part of the proposed library), and you decry that. There's no winning.
+1, I've only been lurking in this conversation, but it seems to me that trying to compete with low level and highly optimized BLAS libraries is a fools errand. John.
But, you making numpy-like library... otherwise you wouldn't be interfacing cblas. A clear case of diyd/diyd ("Damned If You Do, Damned If You Don't"). Of all the features you're missing here you decry "At least show ways to interoperate with existing thirdparty libraries". Now, they went and did that (if I'm not mistaken, clearly marked as an extension that might not even be part of the proposed library), and you decry that. There's no winning.
+1, I've only been lurking in this conversation, but it seems to me that trying to compete with low level and highly optimized BLAS libraries is a fools errand.
Not exactly. And in fact the library has an integration with cblas - which is a good thing to do. However I would expect to see at least "glue" between libraries like OpenCV. As for example numpy as opencv work together seamlessly Anyway there are other issues - as an example I was talking about automatic broadcast adding of shapes (5,1) and (2,5,10) that would normally boradcast automatically to (2,5,10) Something I'd expected to see in such a library Artyom
On Tue, Sep 24, 2024, at 9:09 PM, Artyom Beilis via Boost wrote:
But, you making numpy-like library... otherwise you wouldn't be Anyway there are other issues - as an example I was talking about automatic broadcast adding of shapes (5,1) and (2,5,10) that would normally boradcast automatically to (2,5,10) Something I'd expected to see in such a library
Aren't you still defining "such a library" as the library that it just is not? I didn't see any evidence that arithmetic operations - of any kind - are supplied by the library, other than on iterators/indices. In fact, when scanning the docs, I find: "Unlike FORTRAN, Multi doesn't provide algebraic operators, using algorithms is encouraged instead. For example a FORTRAN statement like A = A + B is translated as this in the one-dimensional case: [...]" Now I may be misunderstanding what you mean by "adding shapes", so maybe you clarify in a way that removes the confusion.
On Wed, Sep 25, 2024 at 1:11 AM Seth via Boost
On Tue, Sep 24, 2024, at 9:09 PM, Artyom Beilis via Boost wrote:
But, you making numpy-like library... otherwise you wouldn't be Anyway there are other issues - as an example I was talking about automatic broadcast adding of shapes (5,1) and (2,5,10) that would normally boradcast automatically to (2,5,10) Something I'd expected to see in such a library
Aren't you still defining "such a library" as the library that it just is not?
I didn't see any evidence that arithmetic operations - of any kind - are supplied by the library, other than on iterators/indices. In fact, when scanning the docs, I find:
Now I may be misunderstanding what you mean by "adding shapes", so maybe you clarify in a way that removes the confusion.
I mean adding tensors/arrays with boradcasting of dimensions as I pointed before (like in np) a = np.zeros((5,1)) b = np.zeros((2,5,10)) c=a+b How do you run it (even with per item Op)? Artyom
On Fri, Sep 20, 2024, at 10:34 PM, Alfredo Correa via Boost wrote:
Thanks,
I did have to supply free function overloads for `rotate` to make the `lu_fact.cpp` example compile. Did something break? This is what I added:
```
namespace boost::multi {
template
participants (4)
-
Alfredo Correa
-
Artyom Beilis
-
John Maddock
-
Seth