Understanding ValArray slices

J

jacob navia

Hi

I have some trouble understanding what are the ValArray slices classes.

Are they just like pointers in the sense that they do not copy the data
but just select it?

Or are they arrays of their own with their own data.

Or do they produce an array of indices?

ValArray classes aren't even mentioned in the C++ Primer book (Lippman
et al) not are they mentioned in the one of Plaugher. The only docs are
some scanty web pages and the standard, what is not that easy to understand.

Thanks in advance for some short tutorial or a pointer to one.

jacob
 
I

Ian Collins

Hi

I have some trouble understanding what are the ValArray slices classes.

Are they just like pointers in the sense that they do not copy the data
but just select it?

They a a collection of indices into a valarray.
Or are they arrays of their own with their own data.

Or do they produce an array of indices?
Yes.

ValArray classes aren't even mentioned in the C++ Primer book (Lippman
et al) not are they mentioned in the one of Plaugher. The only docs are
some scanty web pages and the standard, what is not that easy to
understand.

Thanks in advance for some short tutorial or a pointer to one.

The standard (and excellent) reference is "The C++ Standard Library" by
Nicolai M. Josuttis.
 
J

jacob navia

Le 13/04/11 23:50, Ian Collins a écrit :

Thanks, I see now how this works. The problem is that
it would be more efficient to pass directly the
stride specs instead of allocating the indices array. I will
see how I implement this.

Thanks again Ian
 
G

gwowen

Thanks, I see now how this works. The problem is that
it would be more efficient to pass directly the
stride specs instead of allocating the indices array. I will
see how I implement this.

I think Ian and you are talking at slight cross-purposes.

slices do not themselves, need to store an array of indices, but
rather just the start,end and stride passed at construction time. All
the heavy lifting can be done in the overloaded
valarray::eek:perator[slice], and no intermediate array-of-indices need
creating.

In inefficient semi-pseudo code

valarray<T> valarray::eek:perator[] (slice ...) {
valarray<T> retval(size.size());
size_t retidx = 0;
for(size_t idx = slice.start(); idx < slice.end(); idx +=
slice.stride()){
retval[retidx] = *this[idx];
retidx += 1;
}
}

Of course, one could implement them as generating an array of indices
at construction time, but I doubt that implementations do this. The
fact that operator[] is defined as operating on slice, rather than
const slice& suggests that in the intended implementation slices are
easily copyable.
 
J

jacob navia

Le 14/04/11 10:59, gwowen a écrit :
Thanks, I see now how this works. The problem is that
it would be more efficient to pass directly the
stride specs instead of allocating the indices array. I will
see how I implement this.

I think Ian and you are talking at slight cross-purposes.

slices do not themselves, need to store an array of indices, but
rather just the start,end and stride passed at construction time. All
the heavy lifting can be done in the overloaded
valarray::eek:perator[slice], and no intermediate array-of-indices need
creating.

In inefficient semi-pseudo code

valarray<T> valarray::eek:perator[] (slice ...) {
valarray<T> retval(size.size());
size_t retidx = 0;
for(size_t idx = slice.start(); idx< slice.end(); idx +=
slice.stride()){
retval[retidx] = *this[idx];
retidx += 1;
}
}

Of course, one could implement them as generating an array of indices
at construction time, but I doubt that implementations do this. The
fact that operator[] is defined as operating on slice, rather than
const slice& suggests that in the intended implementation slices are
easily copyable.

OK, this means that in my implementation

MultiplyWith(ValArray *, ValArray*)

would multiply two arrays of the same length

MutiplyWithScalar(ValArray *array,ElementType m)

would multiply an array by a single number and

MultiplyWithSlice(ValArray *array, size_t start, size_t size, size_t
increment, ValArray *multiplicand)

would multiply using the described slice. The multiplicand should have
exactly "size" elements (i.e. as much elements as the slice describes)
 
G

gwowen

Le 14/04/11 10:59, gwowen a crit :
MultiplyWithSlice(ValArray *array, size_t start, size_t size, size_t
increment, ValArray *multiplicand)

would multiply using the described slice. The multiplicand should have
exactly "size" elements (i.e. as much elements as the slice describes)

I'm not sure, I'm afraid. Would this be an "in place" multiplication,
or would MultiplyWithSlice() return a new object/pointer to a new
object?

There's a good example on how to use valarray slices on the MSDN
http://msdn.microsoft.com/en-us/library/5hky5878(v=vs.80).aspx
Essentially, the only (standardised) use of a slice object is an
argument to valarray::eek:perator[] which returns a valarray object whose
size is that of the slice, containing selected elements of the initial
valarray - without modifiying the initial array. Think of it like the
std::string::substr() function, but selecting evenly letters rather
than a substring.

std::string str = "abcdefghijklmnopqrstu";
std::string fragment = str.subtst(1,8); // fragment = "bcdefghi"

// if strings were sliceable
std::string::slice slc(0,8,2); //
fragment = str[slc]; // fragment = "acegikmo"
 
J

jacob navia

Le 14/04/11 18:53, gwowen a écrit :
I'm not sure, I'm afraid. Would this be an "in place" multiplication,
or would MultiplyWithSlice() return a new object/pointer to a new
object?

All the functions of the library are in place functions for the left
argument

Multiply(left,right) means left += right

This allows to build an "accumulator" kind of software in RPN
that is easy to generate and use. You can then express complicated
formulas in that notation without allocating intermediate results.
There's a good example on how to use valarray slices on the MSDN
http://msdn.microsoft.com/en-us/library/5hky5878(v=vs.80).aspx
Essentially, the only (standardised) use of a slice object is an
argument to valarray::eek:perator[] which returns a valarray object whose
size is that of the slice, containing selected elements of the initial
valarray - without modifiying the initial array. Think of it like the
std::string::substr() function, but selecting evenly letters rather
than a substring.

I am not sure it is necessary to have a slice object. If I add 3
arguments to the slice functions it would be the same...

Another (maybe beter) possibility is that ALL functions take
a "slice" argument that defults to
{0,length(ValArray),1} i.e. 0,1,2... length(ValArray)

A function SetSlice(ValArray,start,length,increment) would set a
slice into the array to other values than the default ones, making
that ALL functions would work on the slice automatically.

To take out the slice you would call ReSetSlice(ValArray);

This has the advantage of having less functions and reusing
maybe the same code to work on a slice ithout any
modifications.
std::string str = "abcdefghijklmnopqrstu";
std::string fragment = str.subtst(1,8); // fragment = "bcdefghi"

// if strings were sliceable
std::string::slice slc(0,8,2); //
fragment = str[slc]; // fragment = "acegikmo"

Yes, I see.

Thanks for your input.
 
G

gwowen

Le 14/04/11 18:53, gwowen a crit :



All the functions of the library are in place functions for the left
argument

Right, ok. In which case, yes, everything you say after is right. The
only slight gotcha I can see is that with multiply functions with
slices will, of course, result in the left hand operand getting
resized, but this is also true for standard matrix multiplication.

On a tangent, I can imagine an implementation that provides and easily-
sliceable valarray that stores the the start,stride,size and reindexes
on the fly, in operator[]. Combined with copy-on-write semantics you'd
get cheap slicing, at the cost of an extra multiply-and-add during
indexing. If you slice often (writing a multigrid elliptic PDE solver,
for example) this might be a considerable win... Anyway I'm rambling...
 
J

jacob navia

Le 15/04/11 07:47, gwowen a écrit :
On a tangent, I can imagine an implementation that provides and easily-
sliceable valarray that stores the the start,stride,size and reindexes
on the fly, in operator[].

I am doing exactly that.
 
I

Ian Collins

Le 15/04/11 07:47, gwowen a écrit :
On a tangent, I can imagine an implementation that provides and easily-
sliceable valarray that stores the the start,stride,size and reindexes
on the fly, in operator[].

I am doing exactly that.

In C?
 
G

gwowen

Le 15/04/11 07:47, gwowen a crit :
On a tangent, I can imagine an implementation that provides and easily-
sliceable valarray that stores the the start,stride,size and reindexes
on the fly, in operator[].

I am doing exactly that.

I think Matlab does it too - some of the slicing and selection
operators are incredibly quick - until you have to modify the results,
when all that deferred copying catches up with you. It definitely
works for them, because Matlab is such a good tool for visualising
slices of high dimensional arrays, and since
a) Matlab is clearly inspired by Fortran and
b) Fortran arrays have variable bounds and strides anyway,
I think this must be almost-standard in Fortran.
 
J

jacob navia

Le 15/04/11 22:21, Ian Collins a écrit :
Le 15/04/11 07:47, gwowen a écrit :
On a tangent, I can imagine an implementation that provides and easily-
sliceable valarray that stores the the start,stride,size and reindexes
on the fly, in operator[].

I am doing exactly that.

In C?

For instance:

int Multiply(ValArray *left,ValArray *right);

This will multiply left *= right.

You can set a Slice into a ValArray with:

int SetSlice(ValArray *a,size_t start,size_t length,size_t increment);

From now on, all operations will only use the slice in the array until
you reset it with

int ResetSlice(ValArray *array);

Yes, in C and the main version is in C90, I do not use even my own
extensions to get maximum portability.

In lcc win you will be able to use the overloaded operators, but not in
the versions I will present to the C standards committee.

You can read the docs and download the source code from

http://code.google.com/p/ccl/
 
G

gwowen

For instance:

int Multiply(ValArray *left,ValArray *right);

Is there a reason the second pointer isn't "const" (or are you just
saving typing for these examples)?
 
J

jacob navia

Le 16/04/11 08:05, gwowen a écrit :
Is there a reason the second pointer isn't "const" (or are you just
saving typing for these examples)?

You are right. The second argument should be const

Thanks.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top