Note that there are some explanatory texts on larger screens.

plurals
  1. POEfficiently recalculating the gradient of a numpy array with unknown dimensionality
    primarykey
    data
    text
    <p>I have an N-dimensional numpy array <code>S</code>. Every iteration, exactly one value in this array will change.</p> <p>I have a second array, <code>G</code> that stores the gradient of <code>S</code>, as calculated by numpy's <code>gradient()</code> function. Currently, my code unnecessarily recalculates all of <code>G</code> every time I update <code>S</code>, but this is unnecessary, as only one value in <code>S</code> has changed, and so I only should have to recalculate <code>1+d*2</code> values in <code>G</code>, where <code>d</code> is the number of dimensions in <code>S</code>. </p> <p>This would be an easier problem to solve if I knew the dimensionality of the arrays, but the solutions I have come up with in the absence of this knowledge have been quite inefficient (not substantially better than just recalculating all of <code>G</code>). </p> <p>Is there an efficient way to recalculate only the necessary values in <code>G</code>?</p> <p><strong>Edit: adding my attempt, as requested</strong></p> <p>The function returns a vector indicating the gradient of <code>S</code> at <code>coords</code> in each dimension. It calculates this without calculating the gradient of <code>S</code> at every point, but the problem is that it does not seem to be very efficient.</p> <p>It looks similar in some ways to the answers already posted, but maybe there is something quite inefficient about it?</p> <p>The idea is the following: I iterate through each dimension, creating a slice that is a vector only in that dimension. For each of these slices, I calculate the gradient and place the appropriate value from that gradient into the correct place in the returned vector <code>grad</code>.</p> <p>The use of <code>min()</code> and <code>max()</code> is to deal with the boundary conditions.</p> <pre><code> def getSGradAt(self,coords) : """Returns the gradient of S at position specified by the vector argument 'coords'. self.nDim : the number of dimensions of S self.nBins : the width of S (same in every dim) self.s : S """ grad = zeros(self.nDim) for d in xrange(self.nDim) : # create a slice through S that has size &gt; 1 only in the current # dimension, d. slices = list(coords) slices[d] = slice(max(0,coords[d]-1),min(self.nBins,coords[d]+2)) # take the middle value from the gradient vector grad[d] = gradient(self.s[sl])[1] return grad </code></pre> <p>The problem is that this doesn't run very quickly. In fact, just taking the gradient of the whole array <code>S</code> seems to run faster (for <code>nBins = 25</code> and <code>nDim = 4</code>).</p> <p><strong>Edited again, to add my final solution</strong></p> <p>Here is what i ended up using. This function updates <code>S</code>, changing the value at <code>X</code> by the amount <code>change</code>. It then updates <code>G</code> using a variation on the technique proposed by Jaime.</p> <pre><code> def changeSField(self,X,change) : # change s self.s[X] += change # update g (gradient field) slices = tuple(slice(None if j-2 &lt;= 0 else j-2, j+3, 1) for j in X) newGrads = gradient(self.s[slices]) for i in arange(self.nDim) : self.g[i][slices] = newGrads[i] </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload