OONSTD: Comparison

E. Robert Tisdale (edwin2@gte.net)
Tue, 18 Aug 1998 08:33:49 +0000

The table attached to the end of this message compares Todd Veldhuizen's

blitz++ Array template classes with my proposed SVMT class library
standard.
There is no particular reason for picking on Todd besides convenience.

The first thing that you should notice is that the libraries are very
similar.
Many of the functions have the same name and approximately the same
meaning.
This really shouldn't surprise anyone. A number of conventions have
evolved
during the last decade which have been incorporated into both libraries.

The differences seem to be almost trivial. The blitz++ package is
obviously
a research vehicle which includes many more innovations than SVMT.
Some of these innovations push C++ compiler technology so near the
bleeding
edge that you need one of the newest compilers just to compile blitz++.
The SVMT class library is more concerned with standardization than
innovation.
I have simply tried to extract proven methods from existing class
libraries
and specify a library standard that programmers can use to write high
performance scientific and engineering applications.

The SVMT class library can serve as a basis for other vector, matrix and

tensor class libraries. It should be possible, for example, to derive
Array<double, 1>, Array<double, 2> and Array<double, 3> from
doubleSubVector, doubleSubMatrix, and doubleSubTensor respectively
but it probably wouldn't be practical because of the overhead involved.
The problem is that the blitz++ doesn't distinguish between arrays and
subarrays like SVMT does. Two or more blitz++ Array objects may
reference
the same one dimensional data array. A reference counter is required
to determine when the one dimensional data array should be deallocated.
The obvious advantage of this method is that the one dimensional data
array
is never destroyed before the last Array object which references it.
The disadvantages, besides a small overhead for reference counting,
are less obvious. First, it is difficult for the programmer and
impossible
for the compiler to distinguish arrays from subarrays. Second, there is

no way to determine whether the original array is destroyed before all
of
the subarrays are destroyed which is almost certainly a programming
error.

I am beginning to doubt that CONTAINER-FREE NUMERICAL ALGORITHMS IN C++
will ever be practical. Certainly, template traits won't be sufficient
to substitute SVMT classes into an algorithm that expects services
like those provided by blitz++ Array template classes.
I would need to write an adaptor class to convert one to the other
and I suspect I would need an adapter class for almost any array class
that I wanted to convert to blitz++ Array classes so why should I even
bother with traits? Will writing an adapter class really save me any
time,
effort or money? Wouldn't it be easier to write the array class I
needed
from scratch than to design and build the adaptor class? Bob Tisdale

SVMT blitz++
-------------------------------------------------------------------------------

doubleMatrix M(m, n, 0.0); Array<double, 2> M(m, n); M =
0.0;

M[i][j] = 1.0; M(i, j) = 1.0;

doubleSubVector u = M[i]; Array<double, 1> u = M(i,
Range::all());
doubleSubVector v = M.t()[j]; Array<double, 1> v =
M(Range::all(), j);

doubleSubMatrix B = M; Array<double, 2> B;
B.reference(M);
doubleMatrix A = M; Array<double, 2> A =
M.copy();
or Array<double,
2> B = A; B.makeUnique();

double data[N]; double data[N];
doubleSubArray1 v(data, 0, 1, n); Array<double, 1> v(data, shape(1));

Offset int
Stride int
Length int
Type T_numtype

<Type>Complex complex<T_numtype>
<Type>Handle
MemoryBlockReference<T_numtype>
<Type>SubScalar
<Type>SubVector <Type>Vector Array<T_numtype, 1>
<Type>SubMatrix <Type>Matrix Array<T_numtype, 2>
<Type>SubTensor <Type>Tensor Array<T_numtype, 3>
.handle() .stride()
.offset()
.stride1() .stride() .stride(0)
.stride2() .stride(1)
.stride3() .stride(2)
.extent()
.shape()
.length1() .length() .extent(0) .rows()
.length2() .extent(1) .cols()
.columns()
.length3() .extent(2) .depth()
v.sub(j, s1, n1) v(Range(j, j+n1-1,
s1))

.dimensions() .rank()
.size()
.numElements()
.zeroOffset()

.base()
.base(0)
.base(1)
.base(2)
.lbound(...)

.ubound(...)

.isStorageContiguous()

.makeUnique()
.reference()

allocateArrays(...)

cycleArrays(...)

interlaceArrays(...)
shape(...)

v.sum() v.sum()
M.sum().sum() M.sum()
T.sum().sum().sum() T.sum()
v.min() v.minIndex()
v.max() v.maxIndex()
min(v) v.min()
max(v) v.max()
.ordering()
.reverse1() .reverse(0)
.reverse2() .reverse(1)
.reverse3() .reverse(2)

.reverseSelf(...)
.t() .transpose(0, 1)
.t12() .transpose(1, 0, 2)

.t23() .transpose(0, 2, 1)

.t31() .transpose(2, 1, 0)

.transposeSelf(...)
.ramp()
.swap()
.rotate(...)
.shift(...)
.diag()
.diag12()
.diag23()
.diag31()
.resize() .free()
.resize(n) .resize(n)
.resize(m, n) .resize(m, n)
.resize(l, m, n) .resize(l, m, n)
.even()
.odd()
.real() real(...)
.imag() imag(...)

any(...) any(...)
all(...) all(...)
.aside(...)
.above(...)
.afore(...)
.dot(...)
.kron(...)

.resizeAndPreserve(...)