The DenseSkOp class has complicated semantics for memory management and lazy instantiation. These semantics have so far been governed by the persistent and filled members of DenseSkOp objects. In particular, the current implementation of LSKGE3 inspects these members and decides whether it needs to allocate memory and/or sample random numbers that define the sketching operator. The details of how this currently happens is not very relevant to this PR.
The situation after this PR is merged
This PR removes the persistent and filled members of the DenseSkOp class.
This PR introduces a new function called realize_full that operates on DenseSkOp objects. Calling realize_full(S) populates S.buff as a matrix of size S.n_rows by S.n_cols in S.layout order. It also sets a flag to deallocate S.buff when the destructor is called for S.
Here are the new semantics of LSKGE3, in terms of a DenseSkOp object S.
Scenario 1. If S.buff is not null, then LSKGE3 is not allowed to allocate dynamically sized buffers. We assume that the user called realize_full(S) before calling LSKGE3.
Scenario 2. If S.buff is null, then we have the authority to allocate any memory that we desire inside LSKGE3. We must free this memory before returning. The output of the LSKGE3 must be identical to the output as if we had been in Scenario 1.
The situation before this PR
The
DenseSkOp
class has complicated semantics for memory management and lazy instantiation. These semantics have so far been governed by thepersistent
andfilled
members ofDenseSkOp
objects. In particular, the current implementation of LSKGE3 inspects these members and decides whether it needs to allocate memory and/or sample random numbers that define the sketching operator. The details of how this currently happens is not very relevant to this PR.The situation after this PR is merged
This PR removes the
persistent
andfilled
members of theDenseSkOp
class.This PR introduces a new function called
realize_full
that operates onDenseSkOp
objects. Callingrealize_full(S)
populatesS.buff
as a matrix of sizeS.n_rows
byS.n_cols
inS.layout
order. It also sets a flag to deallocateS.buff
when the destructor is called forS
.Here are the new semantics of LSKGE3, in terms of a
DenseSkOp
objectS
.S.buff
is not null, then LSKGE3 is not allowed to allocate dynamically sized buffers. We assume that the user calledrealize_full(S)
before calling LSKGE3.S.buff
is null, then we have the authority to allocate any memory that we desire inside LSKGE3. We must free this memory before returning. The output of the LSKGE3 must be identical to the output as if we had been in Scenario 1.