Both the left hand side and the right hand side of an assignment operation
must be the same size unless the right hand side is a scalar in which case,
the scalar value is assigned to every element of the left hand side.
For example:
const Length m = 6;
const Length n = 7;
doubleMatrix A(m, n, 1.0); // m by n row major matrix
doubleSubMatrix B = A.t(); // n by m column major matrix
// B references the same 1D array
// referenced by A.
for (Offset i = 0; i < m; i++)
for (Offset j = 0; j < n; j++)
assert(A[i][j] == B[j][i]); // always true
doubleMatrix C = A.t(); // n by m row major matrix
// C references a copy of the 1D array
// referenced by A.
for (Offset i = 0; i < m; i++)
for (Offset j = 0; j < n; j++)
assert(A[i][j] == C[j][i]); // true until A or C is changed
B = 2.0; // assign 2.0 to every element of B
for (Offset i = 0; i < m; i++)
for (Offset j = 0; j < n; j++)
assert(A[i][j] == B[j][i]); // still true
for (Offset i = 0; i < m; i++)
for (Offset j = 0; j < n; j++)
assert(A[i][j] != C[j][i]); // A[i][j] == 2.0 but C[j][i] == 1.0
A = C; // error! A is m by n but C is n by m
A.t() = C; // OK! A.t() and C are both n by m
The assignment operator never changes the size of a vector, matrix or tensor
but application programmers can change the size explicitly using the resize
operator. For example:
A.resize(C); // now A is an n by m row major matrix
// A references a copy of the 1D array
// referenced by C.
B = C; // error! B still references the 1D
// array which has been deallocated
// by A.resize(C).
B.resize(A); // now B references the same 1D array
// referenced by A.
B = C; // OK!
SubVector, SubMatrix and SubTensor objects may have surprising and, we hope,
useful properties because strides can be zero or even negative. For example:
doubleVector R(2*n-1);
R.ramp() -= n-1;
cout << "R = " << setw(2, 2*n-1) << R;
which produces
R = -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6
then, using the constructor
doubleSubMatrix(doubleHandle& h, Offset o, Stride s2, Length n2,
Stride s1, Length n1);
we can view vector R as a matrix:
const
doubleSubMatrix T(R.handle(), n-1, -1, n, +1, n);
cout << "T =\n" << setw(2, n) << T;
which produces
T =
0 1 2 3 4 5 6
-1 0 1 2 3 4 5
-2 -1 0 1 2 3 4
-3 -2 -1 0 1 2 3
-4 -3 -2 -1 0 1 2
-5 -4 -3 -2 -1 0 1
-6 -5 -4 -3 -2 -1 0
Of course, T could appear on the right hand side of an assignment operation
but the result would be undefined if T appeared on the left hand side.
Bob Tisdale