Tools for efficient sparse matrix computation5781779Abstract To generate computationally efficient computer program code for carrying out computer computations on matrix organized input data, a program first is written in a relatively high-level language which includes programmer specifiable constructs for manipulating matrices and parts thereof; and which permits certain of the constructs to be annotated to specify programmer selected data structures and programmer selected operations on those data structures. This high-level program then is translated into a relatively high-level program into a relatively low-level language using low-level language routines that provide a compilable representation of the program, including all programmer selected data structures and all programmer selected operations on said data structures then the low-level representation of the program is compiled to generate computer executable code for implementing the program, including all programmer selected data structures and all programmer selected operations on said data structures. Claims What is claimed: Description BACKGROUND OF THE INVENTION
______________________________________
Syntax:
begin <statement*> end
______________________________________
3.1 Implicit Permutation. This mechanism allows an array to be treated as if it had been permuted.
______________________________________
Syntax:
view <ArrayVariable> through <PermutationVariable*>
<PermutationVariable*> is a list of permutation vectors, one
corresponding to each dimension in the <ArrayVariable>.
______________________________________
This non-executable statement is effective throughout the enclosing lexical scope. A lexical block with such a statement behaves the same way as it would have by replacing all occurrences of <ArrayVariable> with the same variable but with the permutations applied. While this statement has some resemblance to a declaration, it is not one, since it affects the result of the program. Further, it should be noted that this statement differs from replacing the array by its permutation in two ways: At the end of the lexical scope, the permutation is undone. If the permutation is updated while the view is in effect, the effect of the change is seen in array accesses. 3.1.1 Using implicit permutation and no permutation together For those cases where it is useful to view an array both with and without a permutation in the same block, it would be possible to extend the syntax of view . . . through as follows:
______________________________________
view <ArrayVariable> through <Permutation Variable*> as
<OtherArrayVariable>
______________________________________
The declaration is semantically equivalent to replacing all occurrences of <OtherArrayVariable> in the lexical block by <ArrayVariable> with the permutations from <PermutationVariable> applied. 3.2 Declarations In keeping with generally accepted practices, declarations never change the result returned by a program; they only affect efficiency. 3.2.1 Scope All declarations pertain to variables within some lexical scope. 3.2.1.1 Functions A declaration may occur just after a function header, in which case it describes required properties of an argument to the function. Multiple function definitions may be given of the same function. Function invocations will choose among them based on which definition's declarations match the arguments of the call. Note: functions are polyvariant with respect to both types and representations of their arguments. The implementation can compile separate versions of a function for each type and representation that it is called with. 3.2.1.2 Blocks All other declarations have an effect lexically within a block. They must occur before the first use of their variable in the block, and apply to all occurrences of the variable within the block, unless overridden in a contained block. 3.2.2 Type Declarations In order to allow compile-time resolution of ambiguities that might be caused due to the overloaded uses of certain operators/procedure names, a programmer can declare types of variables.
______________________________________
Syntax:
<Type> <Variable*>
<Type>::= {int .vertline. real .vertline. complex} {scalar .vertline.
vector .vertline. row vector .vertline. matrix} .vertline.
permutation .vertline. range
______________________________________
Semantics notes: Vector means column vector. Permutation implies int vector. Range implies int vector. 3.2.3 Representation Declarations These declarations provide a means of specifying alternative representations of arrays.
______________________________________
Syntax:
<Representation> <Variable*>
<Representation>::= {spa .vertline. sparse .vertline. full}
{rows direct}
{columns direct}
{transposed}
{ordered columns}
______________________________________
Semantics notes: The representation declarations are not powerful enough to fully specify what the compiler needs to know about how arrays are represented. Rather, they specify some properties of the representations, which the compiler uses, together with defaults, to determine the full specification of the representation. The previous section describes the full specifications used by the compiler. Rows (columns) direct means that implementation of references to the rows (columns) of the array does not involve an indirection through a permutation vector. The default is to use a direct representation, with two exceptions: in the scope of a view statement, the default is to be indirect on the permutation used in the view; and when passing an indirectly represented matrix to a function, the indirection is preserved. Thus, a direct specification is primarily significant inside the scope of a view statement or for a function that might be called from inside the scope of a view statement. Transposed means that the representation inverts the usual row-column order for that representation. The default is that the representation is not transposed, except for row vectors or when a variable is initialized with the result of the transpose operation. Note that transposed pertains to the representation, not to the indices. In particular, the first index is always the row index and the second is the column index, no matter whether the matrix is transposed. Ordered columns means that the numbers stored with each column are stored in ascending order. The default is not to have columns ordered, but iteration over rows (see below) requires it, and makes this assertion inside its scope. Note: it is possible to allow the converses of the direct, ordered, and transposed declarations, if necessary. 3.3 Special Iterators 3.3.1 Iterators over nonzero elements Iteration over nonzeros.
______________________________________
Syntax:
for nzs <variable> {in order} in <Vector> <Statement*> end
______________________________________
Semantic notes: In successive iterations, <variable> is bound to indices of nonzero elements of <Vector>. If in order is specified, then the indices will be monotonically increasing. Furthermore, if in order is specified and <Vector> is a variable then it is legal to modify elements of <Vector> that lie beyond the index, and the iteration will cover nonzeros added during previous iterations. 3.3.2 Iterators over rows and columns
______________________________________
Syntax:
for (rows .vertline. columns) <variable> in <Array> <Statement*> end
______________________________________
Semantic notes: In successive iterations, <variable> is bound to the indices of successive rows or columns of <Array>. Furthermore, access to the designated row or column should be implemented efficiently, taking advantage of <variable>'s stepping incrementally. The value of <Array> is allowed to change during the loop, but changes behind the current iteration will not be visited, and nonzeros introduced between the current row and the next nonzero will be slow. 3.3.3 Extended version of iterators over rows and columns The construction in the previous subsection is limited in two ways: it cannot handle efficient access to rows of several arrays simultaneously, and it cannot handle efficient access to several rows of one array. To resolve this, it would be possible to extend the language with the following more general declaration:
______________________________________
incremental <Array variable>›<index*>!
______________________________________
Valid instances of this declaration can occur only inside a for statement. Such declarations indicate that access to the specified part of the array should exploit the incrementality of the loop variable. By using several such declarations, a user may specify incremental traversals through several arrays or through several rows of one array. 4.0 Library specification A suitable C++ library for implementing this invention includes the following routines. 4.1 Classes 4.1.1 Types Value--double AbsValue--double Position--int Iteration--int Row--int Column--int 4.1.2 Basic objects SparseMatrix SparseVector SPA FullMatrix FullVector 4.1.3 Miscellaneous objects Range Permutation Enumerator IndexVector NoRange NoPermutation NoEnumerator Operation 4.2 Functionality: In many of the following calls, a matrix argument is followed by a permutation and a range. The semantics is that the result should be as if the order of the rows of the matrix were permuted according to the permutation, and then the set of rows restricted to the range. NoPermutation is a constant indicating the identity permutation, and Norange is a constant indicating the entire range. 4.2.1 class SPA: SPA()--create a SPA of size 0 SPA(int N)--create a SPA of size N .about.SPA()--destroy SPA General functions: void zero()--make the SPA to be empty int size()--returns size of the SPA int nz()--returns number of nonzero elements in the SPA int n.sub.-- explicit--returns number of explicit elements in the SPA Element access member functions: bool is.sub.-- explicit(Position)--is the element explicit? Value get.sub.-- value(Position)--returns value of the element at this Position void change.sub.-- value(Position,Value)--assigns value to the nz element void insert(Position,Value)--assigns value to the implicit element void assign(Position,Value)--assigns value to any element bool is.sub.-- nonzero(Position)--is the element nonzero? Position Iteration2Position(Iteration)--returns value of the index Element access non-member functions: bool is.sub.-- nonzero(SPA&, Row, Permutation,Range) Value get.sub.-- value(SPA&, Row, Permutation,Range) void change.sub.-- value(SPA&, Row, Value, Permutation, Range) void insert(SPA&, int Row, Value,Permutation,Range,Enumerator) void assign(SPA&, int Row, Value, Permutation,Range,Enumerator) Position <-> index functions Position Row2Position(SPA&, Row, Permutation,Range) returns the position corresponding to the row int Position2Row(SPA&, Position pos, Permutation,Range) returns the index of the position Iterator functions Iteration get.sub.-- first(SPA&, Permutation,Range) Iteration get.sub.-- next(SPA&,Iteration, Permutation,Range) bool last(SPA&, Iteration,Permutation,Range) Loading functions void load(SPA&,Permutation,Range,SPA&,Permutation, Range) void load(SPA&, Permutation,Range,SparseVector&, Permutation,Range) void load(SPA&, Permutation, Range,FullVector&, Permutation) 4.2.2 class SparseVector SparseVecotr(SparseMatrix &, int column) creates a SparseVector forthe column of the matrix SparseVector(int n, int nz) creates a SparseVector of size n with the storage for nz explicit elements. General functions int size()--returns the size of the vector int nz()--returns number of the nonzero elements in the vector int n.sub.-- explicit()--returns number of the explicit elements in the vector Element access member functions Value get.sub.-- value(Iteration) Position get.sub.-- position(Iteration) Element access functions Row get.sub.-- row(SparseVector&, Iteration, Permutation, Range) Value get.sub.-- value(SparseVector&, Iteration, Permutation,Range) void change.sub.-- value(SparseVector&, Iteration,Permutation, Range,Value) Iterator functions Iteration get.sub.-- first(SparseVector&, Permutation, Range) Iteration get.sub.-- next(SparseVector&, Permutation, Range, Iteration) bool live(SparseVector&, Permutation, Range, Iteration) 4.2.3 class SparseMatrix Note: In the following, s and one of i or j can be scalars, i.e. I need separate functions SparseMatrix()--creates a matrix with 0 nonzeros SparseMatrix(SparseMatrix&)--creates a copy of the sparse matrix SparseMatrix(FullMatrix&)--creates a sparse matrix from the full matrix SparseMatrix(i,j,s,m,n,nzmax, h) m.times.n matrix with the space for nzmax explicit elements. The elements are ›i,j,s!. h is the headroom vector SparseMatrix(i,j,s,m,n,length(s),h) SparseMatrix(i,j,s, max(i),max(j),length(s),0) SparseMatrix(m,n,z,h)--creates a m.times.n matrix with the space for z nonzeros SparseMatrix(m,n,z) etc. .about.SparseMatrix()--destroys SparseMatrix General functions int size()--returns the size of the square matrix void size(int &m, int& n)--returns the size of any matrix int ncols()--returns number of the columns in the matrix int nrows()--returns number of the rows in the matrix int nz()--returns the number of nonzero elements in the matrix int n.sub.-- explicit()--returns number of explicit elements in the matrix Column functions SparseVector get.sub.-- column(Column j) returns a SparseVector corresponding to the column j Element access functions Value get.sub.-- value(SparseMatrix&, Permutation, Range, Column, Row) void change.sub.-- value(SparseMatrix&, Permutation,Range, Column, Row) void insert.sub.-- value(SparseMatrix&, Permutation,Range, Column, Row) void assign.sub.-- value(SparseMatrix&, Permutation, Range, Column, Row) Load functions void load(SparseMatrix &)--copies a matrix void load(FullMatrix &)--store FullMatrix as SparseMatrix void store(SPA&, Permutation,Range, Column) Structure functions void use.sub.-- sorted.sub.-- columns() void use.sub.-- unsorted.sub.-- columns() Row traversable iterator void setup.sub.-- row.sub.-- iterator() void next.sub.-- row() void is.sub.-- last.sub.-- row() void extract.sub.-- current.sub.-- row(SPA &) Note: it would be desirable to make a row iterator independent of matrix to allow multiple row iterators Submatrix operations assign.sub.-- submatrix.sub.-- right(SparseMatrix& dest, SparseMatrix& source, Permutation, Range, IndexVector row.sub.-- index, IndexVector col.sub.-- index) A=B› . . . !--copies submatrix of the source matrix into the destination matrix assign.sub.-- submatrix.sub.-- left(SparseMatrix& dest, Permutation,Range, SparseMatrix& source, Permutation, Range, IndexVector row.sub.-- index, IndexVector column.sub.-- index) A› . . . !=B--writes source submatrix of the submatrix of the destination matrix assign.sub.-- submatrix.sub.-- both(SparseMatrix& dest, Permutation,Range, IndexVector dest.sub.-- row.sub.-- index, lndexVector dest.sub.-- col.sub.-- index, SparseMatrix& source, Permutation, Range, IndexVector source.sub.-- row.sub.-- index, IndexVector source col.sub.-- index) A› . . . !=B› . . . ! 4.2.4 class FullVector FullVector() FullVector(int size) .about.FullVector() General functions int size()--returns number of elements in the vector int nz()--returns number of nonzero elements in the vector Loading functions load(Permutation&) load(FullMatrix &, Column) load(SparseVector &) load(FullVector &) load(SPA&) Element access functions Value get.sub.-- value(Row, Permutation) Iterator functions Row get.sub.-- first(FullVector&, Permutation) Row get.sub.-- next (FullVector&, Permutation, Row) bool live(FullVector&, Permutation,Row) 4.2.5 class FullMatrix FullMatrix(int ncols, int nrows)--creates a matrix with 0 nonzeros .about.FullMatrix()--destroys FullMatrix General functions int size()--returns the size of the square matrix void size(int &m, int& n)--returns the size of any matrix int ncols()--returns number of the columns in the matrix int nrows()--returns number of the rows in the matrix int nz()--returns the number of nonzero elements in the matrix Column functions FullVector get.sub.-- column(Column j) returns a FullVector corresponding to the column j Element access functions Value get.sub.-- value(FullMatrix&, Permutation, Range, Column, Row) void assign.sub.-- value(FullMatrix&, Permutation, Range, Column, Row) Load functions void load(FullMatrix &)--copies a matrix void load(SparseMatrix &)--store SparseMatrix as FullMatrix Submatrix operations assign.sub.-- submatrix.sub.-- right(FullMatrix& dest, FullMatrix& source, Permutation, Range, IndexVector row.sub.-- index, IndexVector col.sub.-- index) A=B› . . . !--copies submatrix of the source matrix into the destination matrix assign.sub.-- submatrix.sub.-- left(FullMatrix& dest, Permutation,Range, FullMatrix& source, Permutation,Range, IndexVector row.sub.-- index, IndexVector column.sub.-- index) A› . . . !=B--writes source submatrix of the submatrix of the destination matrix assign.sub.-- submatrix.sub.-- both(FullMatrix& dest, Permutation, Range, IndexVector dest.sub.-- row.sub.-- index, IndexVector dest.sub.-- col.sub.-- index, FullMatrix& source, Permutation,Range, IndexVector source.sub.-- row.sub.-- index, IndexVector source col.sub.-- index) A› . . . !=B› . . . ! 4.2.6 class Permutation Permutation()--creates a 0 size permutation descriptor(PD) Permutation (int n)--allocates a PD of size n Permutation (const Permutation &pd)--copies the permutation Permutation (const FullVector & pd)--creates a pd from the full vector .about.Permutation()--destroys the permutation initialize(n)--sets the permutation to be the identity permutation of size n operator=(const FullVector &) operator=(const Range) void swap(int i, int j)--interchanges i and j entries int org2true(int i)--inverse permutation int true2org(int i)--direct permutation Permutation & compose(const Permutation &pd)--applies pd to the current PD bool is.sub.-- permutation() const--checks whether the PD is valid or not 4.2.7 class Range Range()--creates an empty range Range (int f, int l)--creates range ›f:l! Range(const Range &)--copies the range bool within.sub.-- range(int k) const--checks if k is in range set (inf f, int l)--changes the range operator=--copies the range size()--return size of the range int get.sub.-- first()--returns beginning of the range int get.sub.-- last()--return end of the range int get.sub.-- shift()--return index shift imposed by range void set.sub.-- first()--sets the beginning of range void set.sub.-- last()--sets the end of range void has.sub.-- range()--returns true (for compatibility with NoRange) 4.2.8 class Enumerator Enumerators on SPA's will enumerate over new nonzeros are added to the SPA beyond where the enumeration has reached so far. The SPA keeps track of the associated Enumeration object to make this work. Enumerator(SPA&, Permutation, Range) Enumerator(SparseVector&, Permutation,Range) Row get.sub.-- first()--returns and removes the first element in the heap void insert(Row)--inserts element in the heap 4.2.9 class Indexvector IndexVector(int n) .about.IndexVector() int org2true(int i) const 4.2.10 class NoRange bool within.sub.-- range(int k) const {return true;} int get.sub.-- shift() const {return 0;} bool has.sub.-- range() {return false;} 4.2.11 class NoPermutation int org2true(int i) const {return i;} int true2org(int i) const {return i;} 4.2.12 class NoEmumerator void insert(int row) { }; 4.3 Vector traversal functions (search and arithmetic operations) fool (FullVector &, Permutation,Range, Operation, Arguments) foo1(SPA &, Permutation,Range, Operation, Arguments) foo1(SparseVector &, Permutation, Range, NoInsertOperation, Arguments)--Comment: An example is void findMaxAbs(SPA &, Permutation, Range, Position&, Value&) which sets the position and value to the index and value of the largest element. Another is: void divide(SparseVector &, Permutation, Range, Value) which divides each element of the vector by the Value, storing the result back in the vector. foo2(FullVector&, Permutation,Range, const SparseVector&, Permutation,Range, Operation, Arguments) foo2(FullVector&, Permutation,Range, const FullVector&, Permutation,Range, Operation, Arguments) foo2(FullVector&, Permutation, Range, const SPA&, Permutation, Range, Operation, Arguments) foo2(SPA&, Permutation,Range, const SparseVector&, Permutation,Range, Operation, Arguments) foo2(SPA&, Permutation,Range, const FullVector&, Permutation,Range, Operation, Arguments) foo2(SPA&, Permutation, Range, const SPA&, Permutation,Range, Operation, Arguments) Comment: An example is void dpaxpy(SPA&, Permutation,Range, const SparseVector&, Permutation,Range, Value) which multiplies the vector by the value and adds the result to the SPA. foo3(Vector1&, Permutation,Range, const Vector2&, Permutation,Range, const Vector3&, Permutation,Range, Operation, Arguments) with the following rules for Vector1, Vector2 and Vector 3: 1) Vector1 can be either FullVector or SPA 2) Only one of Vector2 or Vector3 can be SparseVector 3) For any combination of Vector2 and Vector3 types, only one type of Vector1 is supported, namely the type of the result of this operation according to AML type resolution rules. Comment: An example is void split(SPA&, Permutation, Range, SparseVector&, Permutation, Range, SparseVector&, Permutation, Range, Position) which sets the first sparse vector to all the nonzeros of the SPA with index less than the position and sets the second sparse vector to all the nonzeros with index greater than or equal to the position.
|
Same subclass Same class Consider this |
||||||||||
