479 max_work: int |
None =
None,
481 """Summarise finished studies in plan order; raise ``WalkforwardError`` on refusal.
483 ``windows`` is a non-empty list or tuple of distinct non-empty labels, and
484 ``sources`` maps supplied labels to complete results, rows lists or file paths.
485 ``metric`` and ``direction`` are required; there is no inferred direction.
486 ``space`` is used only when no source records one. ``max_work`` bounds the
487 declared admission figure, with equality admitted and None unbounded.
489 _options(windows, sources, metric, direction, space, max_work)
490 windows = list(windows)
491 unknown = [label
for label
in sources
if label
not in windows]
494 "walkforward_window_unknown",
495 "sources holds labels absent from the plan",
496 names=sorted(unknown, key=
lambda label: (str(label), type(label).__name__)),
498 supplied = [label
for label
in windows
if label
in sources]
501 "walkforward_no_supplied_sources",
"no plan window has a supplied source"
504 for index, label
in enumerate(windows):
505 if label
not in sources:
508 source = read_source(sources[label], index)
509 check_context(source.rows)
510 except RowsError
as error:
511 raise _reader_error(error, (label,))
from None
512 loaded.append(source)
513 shared, recorded = _space(loaded, windows, space)
514 _direction(shared, recorded, loaded, windows, metric, direction)
515 rows_read = sum(len(source.rows)
for source
in loaded)
518 and metric !=
"objective"
520 row.metrics
is not None and metric
in row.metrics
522 for row
in source.rows
526 "walkforward_metric_unknown",
527 "the metric name is recorded in no row's metrics object",
532 _cells(source, windows[source.index], metric, digests)
for source
in loaded
535 for entry
in state.entries:
537 entry.key = vector_key(entry.row.parameters, shared)
538 except RowsError
as error:
540 "walkforward_input_invalid",
542 (entry.row.trial_id,),
543 (state.label, *error.names),
545 sign = -1.0
if direction ==
"maximize" else 1.0
548 state.selected = min(
550 key=
lambda entry: (sign * entry.value, entry.row.trial_id),
554 for source, target
in zip(states, states[1:]):
555 if target.index != source.index + 1:
558 "from": source.label,
560 "skipped": windows[source.index + 1 : target.index],
563 elif source.selected
is not None:
564 pairs.append((source, target))
565 for source, target
in pairs:
566 eligible = [entry
for entry
in _matches(source, target)
if entry.reason
is None]
567 if eligible
and any(entry.value != eligible[0].value
for entry
in eligible):
569 "walkforward_duplicate_vector",
570 "eligible rows carrying the selected vector record different values",
571 [entry.row.trial_id
for entry
in eligible],
574 rows_eligible = sum(len(state.eligible)
for state
in states)
575 if not rows_eligible:
577 "walkforward_no_eligible_rows",
"no supplied window holds an eligible row"
581 + sum(len(state.eligible) * (len(state.eligible) - 1) // 2
for state
in states)
582 + sum(len(target.eligible)
for _, target
in pairs)
584 if max_work
is not None and work > max_work:
586 "walkforward_resource_exceeded",
587 f
"the admission figure {work} is above max_work {max_work}",
590 "contract": CONTRACT,
593 "direction": direction,
595 "supplied": supplied,
596 "never_run": [label
for label
in windows
if label
not in sources],
597 "rows_read": rows_read,
598 "rows_eligible": rows_eligible,
599 "rows_excluded": rows_read - rows_eligible,
600 "per_window": [_per_window(state)
for state
in states],
601 "carry_over": [_carry(source, target, direction)
for source, target
in pairs],
602 "chain_breaks": breaks,
603 "stability": _stability(states, shared),
605 "algorithm": ALGORITHM,
606 "input_sha256": hashlib.sha256(b
"".join(sorted(digests))).hexdigest(),
607 "interpretation": INTERPRETATION,