Saving DownValues for a function computed in parallel

Is it possible to save DownValues of a function computed using a parallelization routine?

I have a rather costly function f I wish to evaluate at a grid and save the result at each point as its DownValue. Thus I define function f like this:

ClearAll[f]
f[a_] := f[a] = Cos[a]

For the purposes of illustration, Cos is nasty enough. If I try to evaluate:

grid = Table[x, {x, 1, 2, 0.1}];
vals = Parallelize[f[#] & /@ grid];

I have the desired result for vals, but the computed values aren't saved in f:

In:= DownValues[f]
Out= {HoldPattern[f[a_]] :> (f[a] = Cos[a])}

However, I would hope to achieve a result similar to evaluating this function without Parallelize:

In:= grid=Table[x,{x,1,2,0.1}];
vals=f[#]&/@grid;
DownValues[f]
Out= {HoldPattern[f[1.]]:>0.540302,HoldPattern[f[1.1]]:>0.453596,HoldPattern[f[1.2]]:>0.362358,HoldPattern[f[1.3]]:>0.267499,HoldPattern[f[1.4]]:>0.169967,HoldPattern[f[1.5]]:>0.0707372,HoldPattern[f[1.6]]:>-0.0291995,HoldPattern[f[1.7]]:>-0.128844,HoldPattern[f[1.8]]:>-0.227202,HoldPattern[f[1.9]]:>-0.32329,HoldPattern[f[2.]]:>-0.416147,HoldPattern[f[a_]]:>(f[a]=Cos[a])}

So is it possible to parallelize the computation in a way to save these values? I would like to further use the function's value at these points, and it would help me very much if calling f at a point would just look up the already computed result instead of doing the calculation again.

As a side note, I should say that my function is defined with SubValues as f[a_] := f[a] = … and f[a_] := f[a] = …, but above is the minimal non-working example.

I guess it happens because Parallelize uses a separate copy of a context to evaluate f, so all its DownValues are internalized there. Is it possible to collect these contexts somehow or define a DownValue based on the computed vals?

I apologize if I used wrong terminology, and will appreciate your help. Thanks.

• Mathematica uses distributed memory parallelization (please look up the term). The parallel threads do not share variables. I do not have time to write an answer, but these may be a useful read for you: mathematica.stackexchange.com/a/195336/12 mathematica.stackexchange.com/q/48295/12 – Szabolcs Apr 24 at 7:02
• I'd suggest to compute the function once on the whole and to store it in a packed array. Afterwards, you operate only on the array of precomputed values. You should also consider to use Compile your f with options RuntimeAttributes -> {Listable}, Parallelization -> True. This way, you can thread it in parallelized way over the whole grid. – Henrik Schumacher Apr 24 at 7:55
• @HenrikSchumacher Do you suggest to store the function in a way other than the one I used with DownValues? If so, how would you do this? Certainly what you say is what I'd like to achieve, i.e. to operate only on the array of the precomputed values. The issue so far is that these calculated values are not saved due to variables not being shared between threads. Also, thank you for the suggestion to use Compile, but I think it won't work because f is in fact an NIntegrate of another function in my case. – mikeonly Apr 24 at 8:12
• I suggested to compute the values once and store it in an array because the access times for indexing into an array are much faster than into a hash table (the memoized values of f are basically stored in a hash table). Moreover, arrays created in various processes can be simply joined with Join or ArrayFlatten. This is easier than joining the various definitions of f that were created in each process. – Henrik Schumacher Apr 24 at 8:19
• @HenrikSchumacher That makes a lot of sense. I made this choice because of convenience, but with parallelization and access times argument, I see that it is indeed simpler to switch to array. I will need, however, to make a pair {point, value} for that, which should not be hard. And then making a helper function to access these values at a point should simplify things a lot. Thanks! – mikeonly Apr 24 at 8:42