Deep copy warning -- efficient coding?

If I am constructing a symmetric matrix S, typically I have done something like
S[i,j] = complex operation
s[j,i] = s[i,j]

with stan 2.18 this approach generates a lot of warnings. What is the preferred way to approach this?

I think s[j,i] = s[i,j] does not actually trigger a warning, but other things do. The most common way to avoid them is to use foo += bar; rather than foo = foo + bar;. Unfortunately, the Info does not print out the filename or line number, but you can probably figure out where they are.

DIAGNOSTIC(S) FROM PARSER:
Info: left-hand side variable (name=o) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=o) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=o) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=o) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=l) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=DRDI) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=cz1) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=cz0) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=out) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=out) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=covm) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=l) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=l) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=counter) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=counter) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sMANIFESTVAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sT0VAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=state) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=state) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ypredcov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ypredcov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=merrorstates) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfstates) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sMANIFESTVAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=sT0VAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=etacov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=discreteDIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=eta) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=state) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=state) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ypredcov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ypredcov) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=merrorstates) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfmeasures) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=ukfstates) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=pop_DIFFUSION) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=pop_MANIFESTVAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=pop_T0VAR) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.
Info: left-hand side variable (name=popsd) occurs on right-hand side of assignment, causing inefficient deep copy to avoid aliasing.

Thanks, I’m aware of the += and am happy to be able to use that in more cases with 2.18, but still this function generates 4 warnings:

sm <- '
functions{
matrix covsqrt2corsqrt(matrix mat, int invert){ 
        matrix[rows(mat),cols(mat)] o;
        vector[rows(mat)] s;
        o=mat;
      
        for(i in 1:rows(o)){ //set upper tri to lower
          for(j in min(i+1,rows(mat)):rows(mat)){
            o[j,i] = inv_logit(o[j,i])*2-1; 
            o[i,j] = o[j,i];
          }
          o[i,i]=1;
        }
      
        if(invert==1) o = inverse(o);
      
        for(i in 1:rows(o)){
          s[i] = inv_sqrt(o[i,] * o[,i]);
          if(is_inf(s[i])) s[i]=0;
        }
        o= diag_pre_multiply(s,o);
        return o;
}
}
model{
}'

s <- stan_model(model_code = sm)

I think that comes from if(invert==1) o = inverse(o); and o= diag_pre_multiply(s,o); rather than o[i,j] = o[j,i];

That would only generate two warnings by my count, but regardless, the general question still stands – is an operation like:

o = inverse(o)

actually inefficient, and if so, how should one handle this situation?

I think all of the ways to handle that would also involve a copy, although some might avoid the message. You could do something like

if (invert) {
  matrix[rows(o), cols(o)] o_inv = inverse(o);
  ... 
}

Ok. It’s nice that such information is available, but it’s not so nice when it generates a page of spurious warnings that (I think?) can’t be disabled. Also, o[i,j] = o[j,i]; does generate the warning.

They can’t be disabled but they can be avoided. In the loop, maybe try

real tmp = whatever;
o[i,j] = tmp;
o[j,i] = tmp;

Ok, and that should be of equal or greater efficiency? Seems like an extra operation to my naive thinking.

Same efficiency, less warnings about the lack of efficiency.

this is parser bug - https://github.com/stan-dev/stan/issues/2677

1 Like