history - Optimizer evaluation trace¶
History |
Collection of traces. |
Trace |
Value trace. |
Log of progress through a computation.
Each cycle through a computation, a process can update its history, adding information about the number of function evaluations, the total time taken, the set of points evaluated and their values, the current best value and so on. The process can use this history when computing the next set of points to evaluate and when checking if the termination conditions are met. Any values that may be useful outside the computation, e.g., for logging or for updating the user, should be recorded. In the ideal case, the history is all that is needed to restart the process in case of a system crash.
History consists of a set of traces. The content of the traces themselves is provided by the computation, but various stake holders can use them. For example, the user may wish to log the set of points that have been evaluated and their values using the system logger and an optimizer may require a certain amount of history to calculate the next set of values.
New traces are defined using History.provides()
. For example,
the following adds traces for ‘value’ and ‘point’ to the history, and
requires the value on the two previous cycles in order to do its work:
>>> from bumps.history import History
>>> h = History(value=2, point=0) # keep two values and zero points
Initially the history is empty:
>>> print(len(h.value))
0
After three updates we see that only two values are kept.
>>> h.update(value=2.6, point=[1,1,1])
>>> h.update(value=1, point=[1,0.5,1])
>>> h.update(value=0.5, point=[1,0.5,0.9])
>>> print(h.value)
Trace value: 0.5, 1
>>> print(len(h.value))
2
Since the required length of ‘point’ is zero no values are kept:
>>> print(h.point[0])
Traceback (most recent call last):
...
IndexError: point has not accumulated enough history
A history consumer can override this, and require a certain length of a trace. Then future values will be preserved:
>>> h.requires(point=1)
>>> h.update(value=0.25, point=[1,0.5,0.92])
>>> print(h.point[0])
[1, 0.5, 0.92]
Traces are independent of each other. A new trace can be added to the history and updated separately from the existing traces. This can be handy if there are separate sources of history though it may be difficult to keep the in sync. The following adds a ‘step’ to the existing history, initialized to 15, without changing ‘value’ or ‘point’:
>>> h.provides(step=2) # keep two steps
>>> h.update(step=15) # initialize step to 15
>>> print(h.step)
Trace step: 15
Traces may be used as accumulators, with the delta added to the existing value before being stored in the trace. For example:
>>> h.accumulate(step=1)
>>> print(h.step)
Trace step: 16, 15
Within bumps, history is used by monitors, with bumps.fitters.MonitorRunner managing updates to history and feeding them to the fit progress monitors.
-
class
bumps.history.
History
(**kw)[source]¶ Bases:
object
Collection of traces.
Provided traces can be specified as key word arguments, name=length.
-
accumulate
(**kw)[source]¶ Extend the given traces with the provided values. The traced value will be the old value plus the new value.
-
-
class
bumps.history.
Trace
(keep=1, name='trace')[source]¶ Bases:
object
Value trace.
This is a stack-like object with items inserted at the beginning, and removed from the end once the maximum length keep is reached.
len(trace) returns the number of items in the trace trace[i] returns the ith previous element in the history trace.requires(n) says how much history to keep trace.put(value) stores value trace.accumulate(value) adds value to the previous value before storing state = trace.snapeshot() returns the values as a stack, most recent last trace.restore(state) restores a snapshot
Note that snapshot/restore uses lists to represent numpy arrays, which may cause problems if the trace is capturing lists.
-
put
(value)[source]¶ Add an item to the trace, shifting off from the beginning when the trace is full.
-