Push() creates a MStack object on the heap, then inserts it into the stack. However the matrix stored in MStack is a reference to the base vector in the pushed matrix. It also increments Dispatch->stackloc and stores it in the new MStack object. It also stores Dispatch->level in the new object. Dispatch->Push() should be called before calling DecReturn() or ReturnMat().
Earlier versions of Push() had speed problems because Push()
copied its argument into the new stack object. The current
version uses a deep copy technique for
storing stack matrices. The deep copy method boosted the speed
of my programs by about 15 to 20 percent. Push() creates the
reference by a call to the VMatrix function NewReference().
NewReference() increments the
variable nrefs
in the base vector. In the in-ram version,
nrefs
is incremented in the vdoub structure. In the
virtual version, nrefs
is incremented in the hdr
structure. In either case, the base vector is not freed until
nrefs
is zero. However, the rest of the virtual matrix is deleted.
The stack matrices share the base vector with the pushed matrix, and hence you have indirect access to the stack matrix. This access is different from that in Eckle [#!EK:UC!#] where I found the deep-copy technique. Although I can't think of why you would want this access, here is how it can be accomplished.
. . . VMatrix B = Tran(X)*X; Dispatch->Push(B); B.M(1,1) = 2.0; return Dispatch->DecReturn(); }
Note since the stack top matrix shares the base vector with B, the assignment writes 2.0 in both B(1,1) and the (1,1) element of the stack top. Thus the matrix pushed onto the stack will be different from the matrix that is returned by the function call. The only place where this could be a problem is on the stack top and none of the other matrices in the stack. This is because the stack top is the matrix that is returned in function calls. I advise against using this trick. Again I say, Dispatch->Push() should only be called immediately before calling DecReturn() or ReturnMat().
Declevel() decrements the value of level. It is called by DecReturn(). It also stops the program if the nesting level has been decremented to zero. This error indicates that there is a mismatched pair of calls to Inclevel() and DecReturn(), or Inclevel() and Declevel().
Inclevel() increments the function nesting level. Usually Inclevel() is called whenever the function will use a matrix assignment, VMatrix::operator=(). DecReturn() calls Declevel(), so Inclevel() and DecReturn() should be used in pairs. Functions that use matrix assignment or matrix copy constructors do not always return matrices. In this case you should use a pair of Inclevel-Declevel calls to control the stack.
The code for DecReturn() and ReturnMat() is given below by
VMatrix &DecReturn( void ){ Declevel(); next->level = level; return * ((VMatrix *) this->next); } VMatrix &ReturnMat( void ){ next->level = level; return * ((VMatrix *) this->next); }The two functions perform similar functions except that DecReturn() calls Declevel(). They both are called from Dispatch, so *this is actually Dispatch. The functions set level in next to Dispatch->level. You use ReturnMat() if you did not need matrix assignment in a function, and hence did not call Inclevel() at the top. You use DecReturn() if you needed to use matrix assignment hence called Inclevel() at the top. The return statment recasts Dispatch as a VMatrix pointer, and returns the matrix reference stored in next.
while( Dispatch->next->level >= Dispatch->level && Dispatch->next->next) Dispatch->Pop();It calls Pop() while the next stack matrix has a level at least as large as Dispatch->level. It also stops the popping when there is only one matrix left on the stack which is useful when there are problems in the program. This clears the local stack. Recall that Cleanstack() is called by VMatrix::operator=(). The equals operator replaces its left operand by the right before calling Cleanstack(). The left operand is not in the stack, so it is not deleted by Pop().
The copy constructor calls Cleanstack() so it also eliminates temporary matrices. Therefore, you should call Inclevel() and Declevel() if you intend to use the copy constructors.
You may wish to call Cleanstack() occasionally if you are in the
habit of using statements such as
(Tran(X)*X).DispalayMat();
. These
statement–function–calls leave matrices on the
stack which are removed automatically during a matrix
assignment, a copy constructor, or by an explicit call to
Cleanstack().
PrintStack() traverses the stack. It reports the stackloc, level, r, c and name for each matrix in the stack.