Slate++ Vectors and Matrices are set up in the same way other object-oriented objects are constructed. We won't go into great detail about object-oriented programming; rather, we'll show how to use Slate++ through an exhaustive set of examples. In the rest of this tutorial, every example is complete, and located in the directory
/slate/examples/Each example is self-contained, and should be easily compiled and run by a compiler like g++. Hopefully this approach (focusing on learning how to use Slate++ , primarily through example) will prove more useful than describing the internal workings of Slate++ ! On the other hand, we've kept the code documentation fairly clear, so it should be simple for an intermediate programmer to modify Slate++ as he/she feels the need.
#include <slate.h> int main() { // // Vector and Matrix dimensions can be specified on initialization. The // following form makes indices begin at 1. // Matrix<double> a(2,3); Vector<int> b(6); // // Let's specify different ranges on initialization. // Matrix<double> x(6,7,4,6); Vector<int> y(2,7); // // We can use other types if we like. // Matrix<float> r(3,9); Vector<long> p(23); // // Dimensions can also be specified later. // Matrix<double> aa; Vector<int> bb; aa.set_size(1,2,1,3); bb.set_size(1,6); // // The size can be changed numerous times. Let's increase the range // of each dimension in aa and bb by 4. // // NOTE: Changing the size of a Matrix or Vector results in a new // Matrix or Vector being created. If no other Vectors or Matrices // refer to the old data, then it is lost. // aa.set_size(1,6,1,7); bb.set_size(1,10); // // Since the lower indices were 1, we could have written: // aa.set_size(6,7); bb.set_size(10); // // Let's set aa and bb to have the same size as x and y. They will // adopt x and y's index range as well. // aa.set_size(x); bb.set_size(y); // // We can change the offsets anytime. The following makes a and b // have ranges a(10...11, 20...22) and b(-6...-1) // a.new_offset(10,20); b.new_offset(-6); }
Slate++ Vectors and Matrices copy by value. This means that the assignment operator creates a deep copy of all elements, which are then independent of the original.
#include <slate.h> int main() { //////////////////////////////////////////////////////////////////////////// // // Matrices // // // // Matrices can be initialized to a scalar value on construction. The // following creates a 2x3 Matrix with values 19.0. // Matrix<double> a(1,2,1,2,19.0); // // The Matrix elements can be given a different value later. // a = 6.0; // all elements of a are now 6.0 // // Elements can be specified individually. Let's make a unit Matrix. // a = 0.0; a(1,1) = 1.0; a(2,2) = 1.0; // // Let's create some native C arrays, which we'll then assign to a. // double mat1[4] = { 3.0, 4.0, 5.0, 6.0 }; // 1DA matrix a = mat1; cout << a << endl; double *mat2 = new double[4]; // 1DP matrix mat2[0] = 1.0; mat2[1] = 5.0; mat2[2] = 9.0; mat2[3] = 3.0; a = mat2; cout << a << endl; double **mat3 = new (double *)[4]; // 2DP matrix mat3[0] = new double[4]; mat3[1] = mat3[0]+2; mat3[0][0] = 3.0; mat3[0][1] = 4.0; mat3[1][0] = 5.0; mat3[1][1] = 6.0; a = mat3; cout << a << endl; //////////////////////////////////////////////////////////////////////////// // // Vectors // // // // Vectors can be initialized to a scalar value on construction. The // following creates a 3-element with values 19.0. // Vector<double> v(1,3,19.0); // // The Vector elements can be given a different value later. // v = 6.0; // all elements of b are now 6.0 // // Elements can be specified individually. // v(1) = 1.0; v(2) = 1.0; v(3) = 1.0; // // Let's create some native C arrays, which we'll then assign to v. // double vec1[3] = { 3.0, 4.0, 5.0 }; // 1DA vector v = vec1; cout << v << endl; double *vec2 = new double[3]; // 1DP vector vec2[0] = 2.0; vec2[1] = 7.0; vec2[2] = 4.0; v = vec2; cout << v << endl; }
#include <slate.h> #include <fstream> int main() { // "data.txt" contents: // // 2 3 1 2\n // -2 4 -1 5\n // 3 7 1.5 1\n // 6 9 3 7 // import into a slate matrix. ifstream fin1("data.txt"); Matrix<double> m(4,4); // must specify correct dimensions. fin1 >> m; // import into several slate vectors. ifstream fin2("data.txt"); Vector<double> v1(4), v2(4), v3(4), v4(4); // must specify dimensions. // can do one at a time: fin2 >> v1; fin2 >> v2; // ... or can do several on one line, if enough data exists. fin2 >> v3 >> v4; cout << m << endl; cout << v1 << endl; cout << v2 << endl; cout << v3 << endl; cout << v4 << endl; }
#include <slate.h> int main() { // Importing a matrix from stdin. // // Note: row*col entries will be taken from stdin; if too few // are supplied, then the process will block until more entries // are given; if too many are given, the extra will be ignored and // will perhaps end up in the *next* import from stdin! // // Entries will be populated in row-major form. // // Importing works fine with file redirection, pipes, and direct // import from the keyboard. // Matrix<double> m(4, 4); // must specify proper dimensions. cin >> m; cout << "Matrix entered: " << endl; cout << m; // Importing a vector from stdin. // // Note: n entries will be taken from stdin; if too few // are supplied, then the process will block until more entries // are given; if too many are given, the extra will be ignored and // will perhaps end up in the *next* import from stdin! // // Importing works fine with file redirection, pipes, and direct // import from the keyboard. // Vector<double> v(4); // must specify proper dimension. cin >> v; cout << "Vector entered: " << endl; cout << v; }
#include <slate.h> int main() { // // Matrix and Vector elements can be used as lhs and rhs values. // Matrix<float> a(1,4,1,4,2.0); cout << a << endl; a(1,3) = 9.0; cout << a << endl; cout << a(2,2) << endl; Vector<int> b(1,6,0); cout << b << endl; b(3) = 6; cout << b << endl; cout << b(1) << endl; // // We can extract subsets of any Matrix or Vector. Submatrix is // specified as submatrix(low row, high row, low col, high col). // Matrix<float> sub1(2,3); sub1 = a.submatrix(1,2,2,4); // sub1 will start at (1,1) like a cout << sub1 << endl; Vector<int> sub2(2); sub2 = b.subvector(2,4); cout << sub2 << endl; // // We can also take entire rows or columns of Matrices. These are // created as Vectors. // cout << a.row(2) << endl; // a.row(2) is a Vector cout << a.col(3) << endl; // a.col(3) is a Vector }
#include <slate.h> int main() { // // Suppose we have a 5x5 Matrix, with index offset (5,2). // Matrix<float> a(5,9,2,6,2.0); // // We can create an equivalent Vector, where all elements are in a // row-major order. The first index of the Vector will be 1. // Vector<float> b(25); b = a.pack(); cout << a << endl; cout << b << endl; }
#include <slate.h> int main() { // // All Vectors and Matrices (and their elements) can be displayed with // the insertion operator ('<<') to cout: // Matrix<double> a(1,2,1,2,19.0); Vector<float> b(7,10,4.3); a(1,2) = 45.6; b(9) = 12.3; cout << a << endl; cout << b << endl; cout << a(1,1) << " " << a(1,2) << endl; cout << b(9) << " " << b(10) << endl; // // We can also display the number of row and column dimensions of a // Matrix. // cout << a.row_low() << " " << a.row_high() << endl; cout << a.col_low() << " " << a.col_high() << endl; cout << a.row_size() << " " << a.col_size() << endl; // // Total number of elements in a Matrix. // cout << a.size() << endl; // // Dimensions and size of a Vector. // cout << b.low() << " " << b.high() << endl; cout << b.size() << endl; }
When a Slate++ Matrix or Vector is passed into a function, the copy constructor is called, which creates a deep copy of the original Matrix or Vector. Then, whatever is done to the object within the function does not affect the original object. Sometimes you'll want to change the original function rather than make a copy. This is most easily done by passing by reference, as one could do for any C++ object. When one passes by reference, the copy constructor is not called, and the function permanently modifies the original Vector or Matrix. The example below demonstrates both passing by value and passing by reference.
#include <slate.h> // // Sample function which modifies a Matrix by adding 1.0 to each element. // The original Matrix is not changed. // void matmod(Matrix<double> a) { a = a + 1.0; cout << a << endl; } // // Sample function which modifies a Vector by adding 1.0 to each element. // The original Vector is not changed. // void vecmod(Vector<double> v) { v = v + 1.0; cout << v << endl; } // // Sample function which modifies a Matrix by adding 1.0 to each element. // The original Matrix *is* changed, since it's passed by reference. // void matmod2(Matrix<double> &a) { a = a + 1.0; cout << a << endl; } // // Sample function which modifies a Vector by adding 1.0 to each element. // The original Vector *is* changed, since it's passed by reference. // void vecmod2(Vector<double> &v) { v = v + 1.0; cout << v << endl; } int main() { // // Pass a Matrix as a parameter - passing by value (so orig not changed) // Matrix<double> a(1,5,1,5,3.0); matmod(a); cout << a << endl; // // Pass a Vector as a parameter - passing by value (so original not changed) // Vector<double> v(1,6,4.0); vecmod(v); cout << v << endl; // // Pass a Matrix as a parameter - passing by reference (so orig changed) // Matrix<double> a2(1,5,1,5,3.0); matmod2(a2); cout << a2 << endl; // // Pass a Vector as a parameter - passing by reference (so orig changed) // Vector<double> v2(1,6,4.0); vecmod2(v2); cout << v2 << endl; }