PineForge HPO 1.11.0
Native hyperparameter optimization for PineForge strategies
Loading...
Searching...
No Matches
sensitivity.py
Go to the documentation of this file.
1"""Pair ranking and pair maps for the neighbourhood of finished trials (version 1).
2
3A pair map crosses the one-move neighbours of two dimensions around a centre, so
4that the cells off the two axes (the diagonals) show whether two parameters
5interact. It is built after the fact, like the neighbourhood itself: the cells
6are looked up in the rows that were supplied and nothing is evaluated.
7
8The module works on what ``neighbourhood`` produced. The pairs are ranked from
9the per-dimension profile of a centre, the map cells are classified by
10``Study.cell``, and no neighbour is generated here. ``neighbourhood`` calls
11``plan_pairs`` and ``pair_maps`` when ``pair_k`` is above 0; they are public so
12that the ranking and the maps can be read and tested on their own. See
13``docs/sensitivity.md``.
14"""
15
16from __future__ import annotations
17
18from dataclasses import dataclass
19
20from .neighbourhood import (
21 NEVER_EVALUATED,
22 SCORED_INFEASIBLE,
23 SCORED_OK,
24 Study,
25 name_key,
26)
27
28
29
30
31
32
33
34@dataclass(frozen=True)
36 """A ranked pair of dimensions and the values that span its map at a centre.
37
38 ``first`` sorts before ``second`` by byte-wise name. ``first_values`` and
39 ``second_values`` hold the centre's value and its generated neighbours on
40 that dimension, in the dimension's own order (ascending, or declared order).
41 """
42
43 first: str
44 second: str
45 score: int
46 first_values: tuple
47 second_values: tuple
48
49 @property
50 def lookups(self) -> int:
51 """Cells to look up: every cell of the map except the centre cell."""
53
54
55def not_near_counts(profile: dict) -> dict:
56 """Per dimension, the scored neighbours of a centre that are not near the best.
57
58 A scored neighbour is one with status ok or constraint violation. An
59 infeasible neighbour is scored and never near. Unscorable and never
60 evaluated neighbours are not counted.
61 """
62 return {
63 name: sum(1 for cell in cells if cell["class"] in _SCORED and not cell["near"])
64 for name, cells in profile.items()
65 }
66
67
68def rank_pairs(counts: dict, pair_k: int) -> list:
69 """The ``pair_k`` best pairs as (first, second, score), best first.
70
71 The score of a pair is the sum of the not-near counts of its two dimensions.
72 Pairs are ordered by descending score, then by ascending (first, second)
73 name, both byte-wise. Fewer pairs are returned when fewer exist.
74 """
75 names = sorted(counts, key=name_key)
76 pairs = [
77 (counts[first] + counts[second], first, second)
78 for position, first in enumerate(names)
79 for second in names[position + 1 :]
80 ]
81 pairs.sort(key=lambda pair: (-pair[0], name_key(pair[1]), name_key(pair[2])))
82 return [(first, second, score) for score, first, second in pairs[:pair_k]]
83
84
85
86
87
88
89
90def plan_pairs(study: Study, values: dict, profile: dict, pair_k: int) -> list:
91 """Rank the pairs of one centre and span their maps; looks nothing up.
92
93 ``values`` is the centre's normalised vector and ``profile`` its
94 per-dimension neighbour cells as ``neighbourhood`` builds them.
95 """
96 return [
98 first,
99 second,
100 score,
101 _axis(study, values, profile, first),
102 _axis(study, values, profile, second),
103 )
104 for first, second, score in rank_pairs(not_near_counts(profile), pair_k)
105 ]
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143def pair_maps(study: Study, values: dict, plans: list) -> list:
144 """The maps of the planned pairs at one centre, in plan order.
145
146 Cells are in row-major order: the first dimension is the outer loop, each
147 dimension ascending. A cell is the centre, an axis cell (one dimension moved)
148 or a diagonal cell (both moved), and carries the class, objective, gap, near
149 flag and row ids of ``Study.cell``. The diagonal totals count the diagonal
150 cells, those with any row, those scored and those scored near the best.
151 """
152 return [_pair_map(study, values, plan) for plan in plans]
list rank_pairs(dict counts, int pair_k)
list pair_maps(Study study, dict values, list plans)
dict not_near_counts(dict profile)
list plan_pairs(Study study, dict values, dict profile, int pair_k)