Re: Boost Digest, Vol 7730, Issue 1
Alfredo Correa via Boost <[email protected]>
| Newsgroups | gmane.comp.lib.boost.devel |
|---|---|
| Message-ID | <CALy_jFqiFGapz-qNPGT4-iDZTtG38baNeogOrj85hKH3j9w25g@mail.gmail.com> |
Dear Rainer, Thank you again for expanding your review and answer my points. Here is an answer to your last email. > Message: 6 > Date: Tue, 10 Mar 2026 13:37:06 +0100 > From: Rainer Deyke <[email protected]> > Subject: [boost] Re: [multi] Formal Review Begins > To: [email protected] > Message-ID: <[email protected]> > Content-Type: text/plain; charset=UTF-8; format=flowed > > On 3/9/26 20:30, Alfredo Correa via Boost wrote: > >> The proposed library uses an array-of-arrays model. > > > > > > Multi supports both models array-of-array and flattened view this is > > prominently mentioned in the documentation, in the Iteration section ( > > > https://correaa.github.io/boost-multi/multi/tutorial.html#tutorial_iteration > > ) > > My bad. I wrote my first message before fully reading the > documentation, so I (somehow) missed the elements function. > No problem. Sometimes the documentation are not engaging enough to make everything evident at first glance. I changed the "Getting Started" section to mention this right away. For example, I mention that: """" Arrays can be viewed simultaneously as a nested array or as flat set of elemets. ``` assert( A.elements().size() == 6 ); // total number of elements assert( A.elements()[6] == 6 ); assert( &A.elements()[6] == &A[1][2] ); ``` """ Then in the Advanced Usage.Iteration section I now mention your examplesm, and more, using the iterability of the extents object. https://correaa.gitlab.io/boost-multi/multi/tutorial.html#tutorial_iteration > > for(auto indices : a.extensions().elements() ) { > > apply(a, indices) = get<0>(indices) + 10*get<1>(indices); > > } > > I don't see subarray::extensions()::elements in the documentation at > all. In fact, the reference documentation for subarray::extensions() > read "returns a tuple with the extensions in each dimension", and > std::tuple does not have a elements member function. I see one > reference to multi::extensions_t and two references to > subarray::extensions_type, neither of which mentions an elements member > function. So this one isn't my fault. > > I didn't think of using std::apply here. It's a clever solution that > only works because arrays can use operator() for indexing instead of the > more obvious operator[]. That said, I would still prefer the direct > syntax "a[indeces]". > As I said in the correction to my first email, you don't have to use `apply` (there is a `apply_square` planned too). The preferred way is: ``` for(auto [i, j] : a.extensions().elements() ) { a[i][j] = i + 10*j; } ``` The geometric meaning of "rotate" is not limited to 2D. I can rotate an > object in 3D, although I have a lot more choices for the axis of rotation. > The ironic thing is that index rotating can be a geometric rotation of a tensor or an array (after all it is a relabelling of the axis). So the name is not that bad after all. .rotate_indices would be very verbose. I wish there was a pair of unary operator in C++ that can do rotation (of indices) by one and unrotation by one. Something like "a <<" or "a >>". > >> The boost::multi::array::reextent function is not clearly defined. > > > > You will obtain {{1, 2, 0}}, a default element will appear at a[0][2] > > because a[0][2] was not part of the original array. > > > > Your second option depends on some interpretation of the array as flat > > array of numbers. > > I agree that this is the correct behavior, but the documentations should > be more explicit. > ok, it is now clarified. > > > But you can do this better with restrictions, and second, variadic > > templates in a constructor can mess up think in a nasty way. > > multi::array({5, 2}, arg1, arg2, arg3); (to construct elements T{arg1, > > arg2, arg3}). > > Using a restriction eliminates the need for copy construction, but it > still requires move construction. I admit that storing non-movable > types in a multidimensional array is very niche. > Well, restrictions could in principle return r-values. Yes, it is very niche and it is very difficult to make it work and provide useful guarantees. > > Having said that I can add tagged constructor, > `multi::array(std::in_place, > > {5, 2}, arg1, arg2, arg3);` if you think it is something that you need. > > That would solve the problem. > Yes, but it will also prevent extra parameters like allocators. I can experiment a bit with this idea. Also remember that Multi supports partially formed objects. Which in principle means that types that only truly valid after assignment can be manipulated efficiently. > >> On a technical level, the web page doesn't accept arrow keys or page > >> up/down for scrolling, so I have to rely use my mouse for scrolling. > >> > > > > I am able to navigate, scroll up and down with arrow keys, page up/down, > > and space. > > I am using a state of the art (I am told), documentation format (Antora). > > All I can say is that it doesn't work for me on Firefox, my default > browser. It does work on Chromium, so this could be a browser > incompatibility issue or a conflict with one of my browser extensions. > ok, the bug has been reported. > > > >> The boost/multi/elementwise.hpp header is not documented at all in the > >> reference section. > >> > > > > It is documented here: > > > https://correaa.github.io/boost-multi/multi/tutorial.html#tutorial_elementwise > > Yes, but there's no list of functions/operators that the header > includes. Scrolling through the section, I see operators +, *, and /, > as well as function "exp". What other operators are there? I assume > that binary and unary - exist and unary + doesn't, but what about > bitwise operators? Any functions besides "exp"? > > >> The documentation for (I assume) > >> boost::multi::subarray::const_element_ref just calls it element_ref. > >> > > > > For restrictions? not necessarily, depends on the actual element > returned, > > but what is your question? > > On the page, > https://correaa.github.io/boost-multi/multi/reference.html#ref_subarray, > second table, there are two entries for "element_ref". One reads > "Reference to element type, deduced from pointer type, typically T&", > the other reads "Constant reference to element type, deduced from > pointer type, typically T const&". This is an error in the > documentation. The second entry should be labeled "const_element_ref", > not "element_ref". > yes, you are right. fixed. > > >> boost::multi::subarray::index_range and > >> boost::multi::subarray::extension_type are only described in very vague > >> terms. What are the members of these types? > > > > index_range is whatever type you put in the parenthesis notation to > > indicate a range of elements > > > > A( {2, 4} , 5 ); // is the array {A(2 , 5 ), A(3, 5} } > > > > {2, 4} is converted to index_range. > > Sure, but can I do anything else with an index range? Can I access its > members? Can I iterate over it? > yes, yes, and yes. (The members are .front(), .back(), .begin(), .end(), size()) > > > > Extension type is whatever is returned by the .extension() function (this > > is like .size() but returns a range) > > And it apparently has a member function "elements" that is completely > undocumented, given your earlier example: > > > for(auto indices : a.extensions().elements() ) { > > apply(a, indices) = get<0>(indices) + 10*get<1>(indices); > > } > yes, it will be documented > > > >> The return types of boost::multi::subarray::elements and > >> boost::multi::array_ref::elements should be documented. > >> > I will, yes > > > Well the type is a complicated type, that for the most part you don't > need > > to know about. > > > > multi::elements_range_t<int*, multi::layout_t<2, long int> > > > > > It depends on other template parameters. It suffices to know that is a > > random access range. > > So it meets the requirements of std::ranges::random_access_range. Does > it provide indexed access through operator[]? Does copying it produce a > deep or a shallow copy? Is it returned by value or reference? > yes, the copy is deep (it is also immutable). Returns a value, it is a lazy view. > I don't care about the exact type. I care about what properties the > type has. > Fair enough. > > >> boost::multi::restriction has a member function called "home" which > >> "returns an indexable cursor". I don't know what this cursor is, what > >> it does, or what members it has. > a cursor is "a pointer-semantic object to an array that forgot its extents" :) Most users should not need to use it. > > > Cursors are described in other sections. > > I will add a section on the tutorial, its uses are pretty advances. > > For arrays, It is for context in which you can't use pass-by-reference. > > I see a very brief mention of cursors in the Interoperability/CUDA > section (which I skipped over because I am not familiar with CUDA). > They are described as "a multidimensional generalization of iterators". > Based on that description, I would expect being able to point cursors at > different parts of the array (possibly by adding N-dimensional vectors > to the cursor), but there is no such example given. They are also > described as references to arrays that can be indexed and cheaply > copied, but subarray and array_ref can already be used for the same > purpose. > Nope, because subarray and array_ref are not copyable! That is a fundamental design of the library, they are not spans. > Regardless of the purpose of cursors, I expect them to be documented in > the reference section. Other sections of the documentation are fine for > what they are, but the reference section should be able to stand alone. > Yes, that is comming, I am rewriting the reference section. > > > It seems that the main technical criticism was regarding features that > you > > can opt-in, like views, but that you are not forced to use. > > I actually have fairly few technical criticisms. My main problem is > with the documentation is not only inadequate, but inadequate to the > point where I can't even review key design elements without reading the > source code because these design elements are not adequately documented. > For example, I feel that there should be bitwise operators in > multi::elementwise for completeness, but I would have to read the source > code to find out if they already exist or not. > I didn't go overboard because people already complained that there was a lot of operator overloading. So I am now overloading the most requested ones, "I want my D = A + B*C " But you are right, for consistency almost all operators should be there, starting from logical ones. > > The other main issue is naming things, which is of course one of the two > hard problems in computer science. Everything else is basically > nitpicking on my part. > I am collecting alternatives names for everything, so if you have suggestions, please let me know. exfents in place of extensions is underway. > > Direct element access is something that you consider very useful and a > > deal-breaker for any multidimensional library. > > > > I hope I convinced you that element address is a first class citizen in > the > > library and it was a priority since day one. > > Yes, the element address issue is mostly resolved. I still don't like > having to use "std::apply", but I can live with it. > No need to make compromises: ``` for(auto [i, j] : a.extensions().elements() ) { a[i][j] = i + 10*j; } ``` Is there anything specific I could tackle for a recommendation for conditional acceptance, or you think it is irrecoverable? Thank you again, Alfredo _______________________________________________ Boost mailing list -- [email protected] To unsubscribe send an email to [email protected] https://lists.boost.org/mailman3/lists/boost.lists.boost.org/ Archived at: https://lists.boost.org/archives/list/[email protected]/message/X6YKHWN7T76PQFKABOCRD6MFJAD66IKR/