62 trials: Sequence[Mapping[str, Any]],
64 sampler_state: str |
None =
None,
65 symbol_feeds_record: Mapping[str, Any] |
None =
None,
66 data_context: ContinuationDataContext |
None =
None,
68 """Encode every attempted trial in one chunk, sorting rows by uint64 trial ID.
70 Parameters use lexicographic name order. Missing v0.5 constraint values become
71 canonical nulls; feasibility continues to come from state, exactly as in v0.5.
72 Concatenate independent returned blocks without adding separators or a footer.
76 raise ValueError(
"binary block must contain at least one trial")
78 identifier = trial[
"trial_id"]
79 if type(identifier)
is not int
or not 0 <= identifier < (1 << 64) - 1:
80 raise ValueError(
"expected uint64 trial_id with a continuation ID")
81 ordered = sorted(trials, key=
lambda trial: trial[
"trial_id"])
82 identifiers = [trial[
"trial_id"]
for trial
in ordered]
83 if any(left == right
for left, right
in zip(identifiers, identifiers[1:])):
84 raise ValueError(
"duplicate trial_id")
85 parameters = [_parameters(study, trial[
"parameters"])
for trial
in ordered]
86 for trial, values
in zip(ordered, parameters):
87 _validate_data_context(trial, data_context, required=
True)
88 if data_context
is not None:
89 data_context.validate_row(trial, values)
92 state = STATES.index(trial[
"status"])
93 if type(trial[
"feasible"])
is not bool
or trial[
"feasible"] != (state == 0):
94 raise ValueError(
"inconsistent status/feasibility/objective")
96 descriptors = bytearray()
97 columns = [_column(
"Q", identifiers), bytes(states)]
98 for name, parameter
in sorted(study.search_space.items()):
99 kind = {
"integer": 1,
"real": 2,
"boolean": 3,
"categorical": 4}[
102 encoding = 2
if parameter.kind ==
"real" and parameter.step
is None else 1
103 descriptors.extend(struct.pack(
"<BBH", kind, encoding, 0))
104 values = [row[name]
for row
in parameters]
106 columns.append(_column(
"d", values))
108 count = _finite_parameter_cardinality(parameter, name, [])
109 if count
is None or count > 1 << 31:
110 raise ValueError(f
"binary parameter grid index exceeds int32: {name}")
111 if parameter.kind ==
"integer":
113 (value - parameter.low) // parameter.step
for value
in values
115 elif parameter.kind ==
"real":
117 round((value - parameter.low) / parameter.step)
for value
in values
119 for trial, index
in zip(ordered, indices):
122 if parameter.low == parameter.high
123 else _fused_grid_value(index, parameter.step, parameter.low)
125 if index + 1 == count
and decoded > parameter.high:
126 decoded = float(parameter.high)
127 if struct.pack(
"<d", decoded) != struct.pack(
128 "<d", trial[
"parameters"][name]
130 raise ValueError(f
"noncanonical binary grid parameter: {name}")
131 elif parameter.kind ==
"boolean":
132 indices = [int(value)
for value
in values]
137 for index, choice
in enumerate(parameter.choices)
138 if type(value)
is type(choice)
and value == choice
142 for value, index
in zip(values, indices):
143 if type(value)
is float
and struct.pack(
"<d", value) != struct.pack(
144 "<d", parameter.choices[index]
147 f
"noncanonical binary choice parameter: {name}"
149 if any(
not 0 <= index < count
for index
in indices):
150 raise ValueError(f
"invalid binary grid index: {name}")
151 columns.append(_column(
"i", indices))
152 columns.append(b
"".join(_score(trial[
"objective"])
for trial
in ordered))
153 constraint_count = len(study.objective.constraints)
155 for trial
in ordered:
156 values = trial.get(
"constraint_values", [
None] * constraint_count)
157 if not isinstance(values, (list, tuple))
or len(values) != constraint_count:
158 raise ValueError(
"constraint column counts do not match study")
159 constraint_rows.append(values)
160 constraint_order = sorted(
161 range(constraint_count),
162 key=
lambda index: study.objective.constraints[index],
164 for column
in constraint_order:
166 b
"".join(_score(values[column])
for values
in constraint_rows)
170 trial[
"space"].get(
"symbol_feeds")
174 if data_context
is None
177 if data_context
is not None:
178 symbol_feeds_record =
None
179 if symbol_feeds_record
is None and records:
180 symbol_feeds_record = records[0]
181 if any(record != symbol_feeds_record
for record
in records):
182 raise ValueError(
"symbol feeds differ between trial records")
184 isinstance(study.symbol_feeds, Mapping)
185 and study.symbol_feeds.get(
"symbols") == {}
188 study.symbol_feeds
is not None
190 and symbol_feeds_record
is None
191 and data_context
is None
194 "symbol feeds record is required for this study's warm header"
197 if symbol_feeds_record
is not None and not isinstance(
198 symbol_feeds_record, Mapping
200 raise ValueError(
"symbol feeds record must be an object")
201 if symbol_feeds_record
is not None and symbol_feeds_record.get(
"symbols") != {}:
202 encoded = json.dumps(
205 separators=(
",",
":"),
209 if len(encoded) > 8 * 1024 * 1024:
210 raise ValueError(
"symbol feeds header exceeds 8 MiB")
211 runtime = struct.pack(
"<I", len(encoded)) + encoded
214 if data_context
is None
215 else struct.pack(
"<I", 1) + bytes.fromhex(data_context.data_context_sha256)
217 header_bytes = HEADER.size + len(descriptors) + len(runtime) + len(context)
218 if header_bytes >= 1 << 32:
219 raise ValueError(
"binary block header length overflow")
220 payload = b
"".join(columns)
221 header = HEADER.pack(
224 int(bool(runtime)) | (2
if data_context
is not None else 0),
226 header_bytes + len(payload),
228 len(study.search_space),
232 bytes.fromhex(space_hash(study)),
234 block = header + descriptors + runtime + context + payload
235 if sampler_state
is not None:
236 if not isinstance(sampler_state, str)
or not sampler_state:
237 raise ValueError(
"sampler_state must be a nonempty string")
238 state = sampler_state.encode(
"utf-8")
239 if len(state) > 16 * 1024 * 1024:
240 raise ValueError(
"sampler_state exceeds 16 MiB")
241 block += STATE_MAGIC + struct.pack(
"<Q", len(state)) + state
243 except (ValueError, TypeError, KeyError, OverflowError, StopIteration)
as error:
244 raise WarmStartError(f
"warm-start incompatible: {error}")
from error
297 data_context: ContinuationDataContext |
None =
None,
298 symbol_feeds_record: Mapping[str, Any] |
None =
None,
299) -> tuple[dict[str, Any], ...]:
300 """Internal reference reader; public binary preflight still uses the native loader."""
304 names = sorted(study.search_space)
305 constraint_order = sorted(
306 range(len(study.objective.constraints)),
307 key=
lambda index: study.objective.constraints[index],
309 while offset < len(content):
310 if content[offset : offset + 8] == STATE_MAGIC:
311 if len(content) - offset < 16:
312 raise ValueError(
"truncated sampler-state block header")
313 size = struct.unpack_from(
"<Q", content, offset + 8)[0]
315 not 0 < size <= 16 * 1024 * 1024
316 or size > len(content) - offset - 16
318 raise ValueError(
"invalid sampler-state block length")
319 _validate_sampler_checkpoint(
320 content[offset + 16 : offset + 16 + size].decode()
324 if len(content) - offset < HEADER.size:
325 raise ValueError(
"truncated binary block header")
338 ) = HEADER.unpack_from(content, offset)
339 if magic != MAGIC
or version != VERSION
or flags & ~3
or reserved:
340 raise ValueError(
"unsupported binary block magic, version or flags")
341 if digest != bytes.fromhex(space_hash(study)):
342 raise ValueError(
"search space or objective differs (space_hash)")
343 if (parameter_count, objectives, constraints) != (
346 len(constraint_order),
348 raise ValueError(
"binary column counts do not match study")
349 base_header = HEADER.size + 4 * parameter_count
352 or not base_header <= header_size <= block_size <= len(content) - offset
354 raise ValueError(
"truncated or invalid binary block length")
358 if header_size - cursor < 4:
359 raise ValueError(
"truncated symbol feeds header")
360 size = struct.unpack_from(
"<I", content, offset + cursor)[0]
362 if not 0 < size <= 8 * 1024 * 1024
or size > header_size - cursor:
363 raise ValueError(
"invalid symbol feeds header length")
365 content[offset + cursor : offset + cursor + size].decode()
369 if header_size - cursor != 36:
370 raise ValueError(
"invalid data context header length")
371 context_version = struct.unpack_from(
"<I", content, offset + cursor)[0]
372 context_digest = content[offset + cursor + 4 : offset + cursor + 36]
375 or data_context
is None
376 or context_digest != bytes.fromhex(data_context.data_context_sha256)
378 raise ValueError(
"missing or differing data_context_sha256")
380 elif data_context
is not None:
381 raise ValueError(
"bound parent is missing data context identity")
382 if cursor != header_size:
383 raise ValueError(
"invalid binary block header length")
385 if (flags & 1
or data_context
is None)
and (
386 _feed_identity(feeds) != _feed_identity(symbol_feeds_record)
389 "symbol feeds differ from parent (facts or feed values)"
392 row_size = 17 + 8 * constraints
393 for column, name
in enumerate(names):
394 parameter = study.search_space[name]
395 kind, encoding, padding = struct.unpack_from(
396 "<BBH", content, offset + HEADER.size + 4 * column
404 expected_encoding = (
405 2
if parameter.kind ==
"real" and parameter.step
is None else 1
407 if (kind, encoding, padding) != (expected_kind, expected_encoding, 0):
408 raise ValueError(
"binary parameter descriptor differs from study")
409 codecs.append(encoding)
410 row_size += 8
if encoding == 2
else 4
411 if block_size != header_size + count * row_size:
412 raise ValueError(
"invalid binary payload length")
413 cursor = offset + header_size
414 identifiers = struct.unpack_from(f
"<{count}Q", content, cursor)
416 states = content[cursor : cursor + count]
418 values = [{}
for _
in range(count)]
419 for name, encoding
in zip(names, codecs):
420 parameter = study.search_space[name]
421 column = struct.unpack_from(
422 f
"<{count}{'d' if encoding == 2 else 'i'}", content, cursor
424 cursor += count * (8
if encoding == 2
else 4)
425 cardinality = _finite_parameter_cardinality(parameter, name, [])
426 for row, value
in zip(values, column):
428 if cardinality
is None or not 0 <= value < cardinality:
429 raise ValueError(
"invalid binary parameter column")
430 if parameter.kind ==
"integer":
431 value = parameter.low + value * parameter.step
432 elif parameter.kind ==
"real":
435 if parameter.low == parameter.high
436 else _fused_grid_value(
437 value, parameter.step, parameter.low
440 value = min(value, float(parameter.high))
441 elif parameter.kind ==
"boolean":
444 value = parameter.choices[value]
447 def scores() -> tuple[float | None, ...]:
450 for index
in range(count):
451 bits = struct.unpack_from(
"<Q", content, cursor + index * 8)[0]
452 value = struct.unpack_from(
"<d", content, cursor + index * 8)[0]
453 if not math.isfinite(value)
and bits != NULL_BITS:
454 raise ValueError(
"invalid binary objective or constraint value")
455 result.append(
None if bits == NULL_BITS
else value)
459 objectives = scores()
460 constraint_rows = [[
None] * constraints
for _
in range(count)]
461 for original_column
in constraint_order:
462 for row, value
in zip(constraint_rows, scores()):
463 row[original_column] = value
464 for identifier, state, parameters, objective, constraint_values
in zip(
465 identifiers, states, values, objectives, constraint_rows
467 if identifier == (1 << 64) - 1
or state >= len(STATES):
468 raise ValueError(
"invalid binary trial ID or state")
469 parameters = _parameters(study, parameters)
471 "trial_id": identifier,
472 "status": STATES[state],
473 "feasible": state == 0,
474 "objective": objective,
475 "parameters": parameters,
476 "constraint_values": constraint_values,
478 if data_context
is not None:
479 row.update(data_context.row_identity(parameters))
483 raise ValueError(
"binary history contains no trials")
484 rows.sort(key=
lambda row: row[
"trial_id"])
486 left[
"trial_id"] == right[
"trial_id"]
for left, right
in zip(rows, rows[1:])
488 raise ValueError(
"duplicate trial_id")
498 raise WarmStartError(f
"warm-start incompatible: {error}")
from error