Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retaining original class with 1D vectors #105

Open
DavisVaughan opened this issue Apr 5, 2019 · 0 comments
Open

Retaining original class with 1D vectors #105

DavisVaughan opened this issue Apr 5, 2019 · 0 comments

Comments

@DavisVaughan
Copy link
Contributor

DavisVaughan commented Apr 5, 2019

When you do something like this, the types change when they really shouldn't:

x <- 1:5
rray_abs(x) # using xtensor::abs()

x is an "integer" and the result of rray_abs(x) is an "array" class holding an integer. These behave slightly differently, and it is enough that I think it would be nice if we could return an "integer" for this kind of thing.

After some searching, I learned that this happens because of this line in init_from_shape():
https://github.com/QuantStack/xtensor-r/blob/9c13372e72b76792fa3abead8a7546a8d0cbc9ca/include/xtensor-r/rarray.hpp#L189

If the shape.size() > 0 we currently always create an R "array".

I want something sort of like this. If it sees that shape.size() == 1, then it knows it can just make an R vector instead, using Rf_allocVector(). The thing that doesn't work here is that if you start with an "array" that is 1D like array(1:5) and then do rray_abs(array(1:5)), it will return an "integer" (because shape.size() == 1), rather than an array.

    template <class T>
    template <class S>
    inline void rarray<T>::init_from_shape(const S& shape)
    {
        if (shape.size() == 0)
        {
            base_type::rstorage::set__(Rf_allocVector(SXP, 1));
        }
        else if (shape.size() == 1) 
        {
            Rcpp::IntegerVector tmp_shape(shape.begin(), shape.end());
            base_type::rstorage::set__(Rf_allocVector(SXP, tmp_shape[0]));
        }
        else
        {
            Rcpp::IntegerVector tmp_shape(shape.begin(), shape.end());
            base_type::rstorage::set__(Rf_allocArray(SXP, SEXP(tmp_shape)));
        }
    }

I think we need to record if the SEXP is an "array" at creation, checking with Rf_isArray() which looks for a "dim" attribute, and then the condition can be:

else if(shape.size() == 1 && !was_originally_an_array)

I don't know quite enough about where I'd add that boolean flag of whether or not it was originally an array, and where I'd have to update it in the constructors and so on. Some help there would be great, and then I could attempt a PR if you are okay with this idea.

I would also love a pointer on how to coerce shape into an integer more gracefully than what I am doing here. Rf_allocVector() takes an R_xlen_t for its second argument, and that can be just an int, so if you could tell me how to go from shape of size 1 -> int that would be great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant