MATLAB: How to avoid a redundant for-loop in generated code that computes the virtually unused quantity ‘trueCount’

ccodecodegengenerationindexinglogical?loopmatlab coder

For the following lines:
stopEdgeIdx = stopEdgeIdx(stopEdgeIdx <= globalMaxIndx);
if ~isempty(stopEdgeIdx)
<< do something >>
end
The generated C code contains two loops, which seems redundant:
k = trueCount - 1;
trueCount = 0;
for (b_i = 0; b_i <= k; b_i++) {
if (stopEdgeIdx_data[b_i] <= globalMaxIndx) {
trueCount++;
}
}
partialTrueCount = 0;
for (b_i = 0; b_i <= k; b_i++) {
if (stopEdgeIdx_data[b_i] <= globalMaxIndx) {
stopEdgeIdx_data[partialTrueCount] = stopEdgeIdx_data[b_i];
partialTrueCount++;
}
}
Is there a way to have only one loop instead of two?

Best Answer

Development is aware of this issue and will consider fixing it in a future release of MATLAB. In the meantime, you could generate a dynamic array to eliminate one of the for-loops, but there is a memory tradeoff. Here is a contrived example:
function out = Example1(stopEdgeIdx, globalMaxIndx)
stopEdgeIdxTemp = [];
for elem = stopEdgeIdx
if(elem <= globalMaxIndx)
stopEdgeIdxTemp = [stopEdgeIdxTemp elem];
end
end
if ~isempty(stopEdgeIdxTemp)
% <do something> region

out = sum(stopEdgeIdxTemp);
else
out = 0;
end
end
The generated code has a single for-loop and stopEdgeIdxTemp is a dynamically sized array:
...
for (vlen = 0; vlen < 6; vlen++) {
if (stopEdgeIdx[vlen] <= globalMaxIndx) {
k = stopEdgeIdxTemp->size[1];
i = stopEdgeIdxTemp->size[0] * stopEdgeIdxTemp->size[1];
stopEdgeIdxTemp->size[1]++;
emxEnsureCapacity_real_T(stopEdgeIdxTemp, i);
stopEdgeIdxTemp->data[k] = stopEdgeIdx[vlen];
}
}
...
The call to 'emxEnsureCapacity_real_T' during each loop iteration may be expensive, however. To avoid this, you can try pre-allocating with coder.nullcopy:
function out = Example2(stopEdgeIdx, globalMaxIndx)
StopEdgeIdxTmp = coder.nullcopy(zeros(1, length(stopEdgeIdx)));
k = int32(1);
for elem = stopEdgeIdx
if elem <= globalMaxIndx
StopEdgeIdxTmp(k) = elem;
k = k + 1;
end
end
StopEdgeIdxTmp = StopEdgeIdxTmp(1:k);
if ~isempty(StopEdgeIdxTmp)
% <do something> region
out = sum(StopEdgeIdxTmp);
else
out = 0;
end
end
The generated code will depend on whether the size of stopEdgeIdx is known at compile time. For the example above, then the generated C code has only 1 for-loop (plus the '<do something>' region) with no dynamic arrays:
...
double StopEdgeIdxTmp[6];
k = 1;
for (elem = 0; elem < 6; elem++) {
if (stopEdgeIdx[elem] <= globalMaxIndx) {
StopEdgeIdxTmp[k - 1] = stopEdgeIdx[elem];
k++;
}
}
/* <do something> region */
elem = (signed char)k;
out = StopEdgeIdxTmp[0];
for (k = 2; k <= elem; k++) {
out += StopEdgeIdxTmp[k - 1];
}
...