The IotrVector class implements an abstract vector class, without many assumptions on the capabilities of vectors or how they are stored. Most importantly, there is no single operator that allows random access to the elements of an IotrVector. We encourage the use of higher-level operations, such as BLAS operations, on vector objects.
The SimpleVector class is a class that explicitly assumes that the elements of a vector are stored in contiguous memory and that random access is possible. As might be expected, SimpleVector objects respond to operator[]
.
Any subclass of IotrVector must provide methods that copy the elements of an instance of the class to or from a SimpleVector.
class MyVector : public IotrVector { ... virtual void copyFrom( const SimpleVector & v ); virtual void copyInto( const SimpleVector & v ); };
Also, for debugging purposes, a vector class must provide the inspect
and inspectAsMatlab
classes.
class MyVector : public IotrVector { virtual void inspect( const char * name = 0, const char * filename = 0 ) const; virtual void inspectAsMatlab( const char * name = 0, const char * filename = 0) const; };
name
can be used to supply the name that will be used when the vector is displayed. This is particularly useful with the inspectAsMatlab method, which will generate code for creating a vector of that name. The filename
parameter is the name of a file into which to save the data. This option is useful if the vector is large. If the first two characters of filename
are >>
then those characters will be removed and the data will be appended to the file of the resulting name. Otherwise the file named filename
will be overwritten. When called from a debugger, these methods should be invoked in one of the three following ways. (gdb) call v.inspect(0,0) (gdb) call w.inspect("w", 0) (gdb) call z.inpsect("z", "z" )
It is not expected that different types of vectors will be able to interoperate seemlessly. For instance, one would be unlikely to implement an operation that could multiply each component of a SimpleVector by the corresponding component of a distributed vector, because such an operation would be unwise and better flagged as an error. Typically, applications will use at most two subclasses of IotrVector: SimpleVector and possibly a specialized class of vector tailored to the problem. For instance a parallel implementation might use a vector class that represented a distributed vector, and use SimpleVector to refer to a vector stored locally.
Because Iotr uses inheritance, rather than templates, to create new vector classes, it is not always possible for the C++ compiler to verify statically that operations between two vectors are permitted. To use the example above, operator+=
is defined as
class IotrVector : public IotrRefCount { virtual IotrVector& operator*=( const IotrVector& v ) = 0; };
void myFunction( IotrVector & v, IotrVector & w ) { v += w; }
v
has actual type SimpleVector but w
is some sort of distributed vector. The C++ compiler, however, cannot detect this incompatibility.
Low-level code that manipulates vectors, such as the code that is written to implement a subclass of IotrVector, often needs greater access to the elements of a vector than the methods of IotrVector provide. Thus, it would be common to implement operator *=
as follows.
class MyVector : public IotrVector { ... IotrVector& operator*=( const IotrVector& v ); }; IotrVector& MyVector::operator*=( const IotrVector& av ) { MyVector & v = dynamic_cast<MyVector &>(av); ... return *this; }
dynamic_cast
is a run-time check that the vectors are compatible.