| Sparse Vectors |
VL contains both a sparse vector type, which stores only the non-zero elements of the vector, and a sparse matrix type, whose rows are sparse vectors. Sparse vectors can be efficiently combined with other sparse vectors or normal vectors using the standard vector operations:
SparseMatf sm; SparseVecf sv1, sv2, sv3; Vecf v;
v = sm * v; sm[0] += v; sv1 = sv2 + sv3;
| Initialisation |
Sparse vectors are typically initialised by giving a list of index, element pairs:
SparseVecf sv; // unsized sparse vector SparseVecf sv(20); // zero vector of length 20. SparseVecf sv(5, 1, 1.0, 2, 2.0, VL_SV_END); // the vector [0.0, 1.0, 0.0, 0.0 4.0]The standard vector initialisers can also be used.
| Manipulation |
Once you have your sparse vector, it can be changed in the following ways:
* Re-initialise with the SetElts() method:
sv.SetSize(5); sv.SetElts(1, 1.0, 4, 4.0, VL_SV_END); // sets sv to [0.0, 1.0, 0.0, 0.0 4.0]
* Use the SVIter[fd]
iterator, which lets you iterate over the elements of a sparse vector,
and access them using the methods:
j.Data() : returns the current element's dataNote: It is highly recommended that you use the SVIter[fd] class to manipulate sparse vectors, as it is written to be as efficient as possible, even performing a binary search for elements when necessary. The iterator class can be used in a number of ways:
j.Index() : returns the current element's index
* Use Begin(), Inc(), AtEnd() to iterate over the non-zero elements of the vector:* Use the Overlay() method: a.Overlay(b) performs a[i] = b[i] for all non-zero b[i].SVIterf j; // sv = sv * 2 for (j.Begin(sv); !j.AtEnd(); j.Inc()) j.Data() *= 2.0;* Use one of the following methods:Inc(Int i) moves on to elt i, where i will increase by 1 on each call IncTo(Int i) moves on to elt i, where i will increase monotonicallywithin another for-loop to access the elements of the sparse vector corresponding to i. For example:// v = v + sv for (j.Begin(sv), i = 0; i < v.NumItems(); i++) { j.Inc(i); v[i] += j.Data();} // a += dot(sv1, sv2) for (j.Begin(sv2), k.Begin(sv1); !k.AtEnd(); k.Inc()) { j.IncTo(k.Index()); // find corresponding elt in sv2 if (j.Exists()) a += j.Data() * k.Data(); }
* Direct access: Begin(), AddElt() or AddNZElt() new element pairs in order, then call End(). (Use AddNZElt() if you know for certain the added element will be non-zero.) For example:
// set sv to [0.0, 1.0, 0.0, 0.0 4.0] sv.NumElts(5); sv.Begin(); sv.AddNZElt(1, 1.0); sv.AddNZElt(4, 4.0); sv.End();* As a last resort, use the Get() and Set() methods. These calls are not efficient for multiple accesses, but will at least perform a binary search to locate the requested element quickly.
sv1.Set(10, sv2.Get(20)); // sv1[10] = sv2[20]Note: The best way to write code for sparse vectors and matrices is to use the SVIter[fd] class, and recast code to use the efficient vector operations where possible.
| Sparse Fuzziness |
The SparseVec class has a tolerance level for elements to be considered zero, referred to as the fuzz. (If |x| < fuzz, it is treated as zero.) This can be set with the method SparseVec[fd]::SetFuzz(fuzz). The default value of fuzz is 1e-10.
A convenient way to test if an element is zero according to the current
fuzz setting is to use the SparseVec[fd]::IsNonZero(elt) method.
|
|