Improving handling of ranges (was: Re: mutable considered harmful, Range edition)
"John W. Eaton" <[email protected]>
| Newsgroups | gmane.comp.gnu.octave.maintainers |
|---|---|
| Message-ID | <[email protected]> |
On 6/9/20 9:43 AM, I wrote:
> On 6/9/20 12:11 AM, I wrote:
>
>> Separately, I see that other than the Range::matrix_value method, we
>> set the cache value in the operators, like this:
>>
>> Range operator + (const Range& r, double x)
>> {
>> Range result (r.base () + x, r.limit () + x, r.inc (), r.numel ());
>> if (result.m_numel < 0)
>> result.m_cache = r.matrix_value () + x;
>>
>> return result;
>> }
>>
>> As I recall, setting the cache in these functions (and not just the
>> matrix_value method) is done so that, for example, adding a constant
>> to a range and then converting to a matrix will produce exactly the
>> same result as converting a range to a matrix and then adding a
>> constant to the matrix (in psuedo code):
>>
>> matrix (r) + c == matrix (r + c)
>>
>> Using the cache this way does avoid the cost of any repeated
>> conversions to a matrix value, but it also forces the cache to be
>> created for any operation on a range, not just the result. So it
>> largely defeats the purpose of the efficient range object storage, and
>> I'm wondering whether it is worth having a special range data type at
>> all? What do we really gain for the additional complexity?
>
> I see now that there are limited cases where result.m_numel will be
> negative, so the cache is not updated for every operation. However, the
> problems with the mutable cache remain, as do the issues with operations
> on ranges not being identical to the operations on the equivalent
> matrices. Here is a simple example:
>
> r0 = 1:0.1:10;
> r1 = r0 + 2.3; # range + scalar
> r2 = [r0] + 2.3; # matrix + scalar
> all (r1 == r2) # returns false for me
> d = r1 - r2; # show elements with differences
> idx = find (d)
> d(idx)
>
> I understand the arguments about Octave being a numerical tool and not
> expecting exact results for floating point operations, but I'm still
> wondering whether the complexity of these range operations is justified.
> If we do want to support operations that avoid immediate conversion to
> Matrix data, maybe we should only do so when we can guarantee that
>
> matrix (r) OP val == matrix (r OP val)
>
> is true? We should be able to do this when VAL and all elements of R
> are integers and will remain so after the operation. Other cases might
> be possible as well, but harder to detect. And maybe the cache should
> be eliminated and this test handled in the octave_value class hierarchy?
Are there any thoughts on this topic?
At the very leas, I would like to support integer ({u,}int{8,16,32,64})
and single-precision ranges in Octave. If possible, I'd like to have a
unified solution for all range types, but that might be a somewhat
disruptive change.
Comments would be helpful.
jwe