I'm sure there must be more elegant solutions than this, but if each step takes significant time, then saving the intermediate results to disk ( or better still a RAM disk or solid state disk ) shouldn't be too much of an overhead.
The benefit here is this is partially resistant to some forms of system lockup or crash.
I've used Nest
but no reason this couldn't be done with Table
as well.
NestWhileList[
With[{res = #[[2]][Last@#]}, #[[2]] >>
"int_res_" <> ToString[Last@#]; {Append[First@#, res], #[[2]],
Last@# - 1}] &, {{}, Sin, 10}, Positive@Last@# & ]
In this example Sin
represents a placeholder which can be exchanged for your function of choice.
Reflection suggests that extending this to allow restarting might be a wothwhile exercise.
Update
Kernel Crash Resilient Function Application
Here is a naive, but hopefully useful, stateful solution to applying a time expensive function to a set of parameters or integers that is robust to interrupts and kernel crashes and is similar in spirit to Map
or Table
.
The approach is to maintain an externally stored state vector of the progression through the computation. The state vector collects the list of results and holds the unevaluated parameters and applied function.
A history option can be used to store the state for each step, allowing computation to be restarted from anywhere in the sequence.
Support is provided for named execution threads.
Basic usage
AirBag[Block[{}, Pause[#]; Print@#; #] &, {1, 3, 5, 7, 5, 3, 2}]
1
3
Out[335]=$Aborted
AirBag[]
5
7
5
3
2
Out[336]={1, 3, 5, 7, 5, 3, 2}
Named execution threads
AirBag[Composition[#^2 &, Plus], {{2, 3}, {3, 3}, {1, 4}, {5, 7}, {6, 7}},
History -> True, FileSpec -> "./air_bag_composite."]
{25, 36, 25, 144, 169}
Restart the named execution thread from an arbitrary step:
AirBag["./air_bag_composite.3"]
{25, 36, 25, 144, 169}
Clear@AirBag;
Options@AirBag = {FileSpec -> "./air_bag_int_res.", History -> False};
(* Process a state vector -> {results list, function, parameter list, \
iteration counter } *)
AirBag[state_List, OptionsPattern[]] :=
NestWhile[
With[{res = #[[2]][Sequence @@ (First@#[[3]])]}, {Append[First@#,
res], #[[2]], Rest@#[[3]], Last@#} >>
OptionValue@FileSpec <>
If[OptionValue@History, ToString[Last@#], "1"]; {Append[First@#,
res], #[[2]], Rest@#[[3]], Last@# + 1}] &, state,
Length@#[[3]] > 0 &]//First
(* Apply function to the integers 1 to iterations *)
AirBag[function_, iterations_Integer, opts : OptionsPattern[]] :=
AirBag[function, Range@iterations, opts]
(* Apply function to a list of parameter values *)
AirBag[function_, parameters_List, opts : OptionsPattern[]] :=
AirBag[{{}, function, parameters, 0}, opts]
(* Restart from a saved AirBag state *)
AirBag[fileName_String, opts : OptionsPattern[]] :=
If[FileExistsQ@fileName,
With[{state = Get@fileName}, AirBag[state, opts]]]
AirBag[OptionsPattern[]] := AirBag[OptionValue@FileSpec <> "1"]