feat(adr-0242): Drive V1 cert discipline + doc align five vectors
Close the gap between cohesion packing/search and Drive ADR-0242:
D0 — Expand ADR-0242 to five-vector + sovereignty thesis (title matches Drive).
D8 — Land docs/analysis/fibonacci_applications_in_core_substrate.md.
D1 — FibonacciSearchCertificate | OptimizationFailure (never bare float);
content-addressed cert_id; dual-run stable digest.
D2 — propose_kappa_from_search / goldtether.propose_kappa_line_search;
failure → baseline κ=1.0 (no state mutation).
D4 — ALLOCATOR_VERSION golden_angle_v1 + layout descriptor.
Fidelity §12 honest: V1/V3 green; V2 table-only; V4/V5 staged.
This commit is contained in:
parent
9d543f6a9c
commit
bbd3b6678f
9 changed files with 599 additions and 119 deletions
|
|
@ -33,6 +33,7 @@ from core.physics.goldtether import (
|
|||
GoldTetherMonitor,
|
||||
OperatingMode,
|
||||
coherence_residual,
|
||||
propose_kappa_line_search,
|
||||
)
|
||||
from core.physics.dynamic_manifold import (
|
||||
AxisClassification,
|
||||
|
|
@ -91,7 +92,15 @@ from core.physics.wave_energy_boundary import (
|
|||
recency_band_index,
|
||||
wave_unitary_residual,
|
||||
)
|
||||
from core.physics.fibonacci_search import fibonacci_number
|
||||
from core.physics.fibonacci_search import (
|
||||
BASELINE_KAPPA,
|
||||
BoundedUnimodalObjective,
|
||||
FibonacciSearchCertificate,
|
||||
OptimizationFailure,
|
||||
fibonacci_number,
|
||||
fibonacci_section_search,
|
||||
propose_kappa_from_search,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"SalienceOperator", "SalienceMap", "FieldRegion",
|
||||
|
|
@ -134,4 +143,11 @@ __all__ = [
|
|||
"recency_band_index",
|
||||
"wave_unitary_residual",
|
||||
"fibonacci_number",
|
||||
"BASELINE_KAPPA",
|
||||
"BoundedUnimodalObjective",
|
||||
"FibonacciSearchCertificate",
|
||||
"OptimizationFailure",
|
||||
"fibonacci_section_search",
|
||||
"propose_kappa_from_search",
|
||||
"propose_kappa_line_search",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ from core.physics.wave_manifold import WaveManifold
|
|||
|
||||
PHI = (1.0 + math.sqrt(5.0)) / 2.0
|
||||
DEFAULT_MIN_D = 0.12
|
||||
# Reconstruction-over-storage: layout regenerates from identity + ordinal k.
|
||||
ALLOCATOR_IDENTITY = "golden_angle"
|
||||
ALLOCATOR_VERSION = "golden_angle_v1"
|
||||
|
||||
|
||||
class AtlasPackingError(ValueError):
|
||||
|
|
@ -54,6 +57,9 @@ def golden_angle_pack(
|
|||
(x,y) = (r cos θ, r sin θ) → embed_point → null 32-vector
|
||||
|
||||
Rejects with :class:`AtlasPackingError` if any pairwise separation < min_d.
|
||||
|
||||
Layout is reconstructible from :data:`ALLOCATOR_VERSION` and ordinals
|
||||
``0..n-1`` (no opaque mutable coordinate table as truth).
|
||||
"""
|
||||
if n < 1:
|
||||
raise AtlasPackingError("n must be >= 1")
|
||||
|
|
@ -83,6 +89,24 @@ def golden_angle_pack(
|
|||
return modes
|
||||
|
||||
|
||||
def allocator_layout_descriptor(
|
||||
n: int,
|
||||
alpha: float,
|
||||
*,
|
||||
min_d: float = DEFAULT_MIN_D,
|
||||
) -> dict[str, object]:
|
||||
"""Content-free reconstruction metadata for packing (no coordinate leak)."""
|
||||
return {
|
||||
"allocator_identity": ALLOCATOR_IDENTITY,
|
||||
"allocator_version": ALLOCATOR_VERSION,
|
||||
"n": int(n),
|
||||
"alpha": float(alpha),
|
||||
"min_d": float(min_d),
|
||||
"metric": "cga_null_point_euclidean_d",
|
||||
"note": "not_full_H2_geodesic",
|
||||
}
|
||||
|
||||
|
||||
def register_packed_modes(
|
||||
modes: Sequence[np.ndarray],
|
||||
manifold: WaveManifold,
|
||||
|
|
@ -101,8 +125,11 @@ def register_packed_modes(
|
|||
__all__ = [
|
||||
"PHI",
|
||||
"DEFAULT_MIN_D",
|
||||
"ALLOCATOR_IDENTITY",
|
||||
"ALLOCATOR_VERSION",
|
||||
"AtlasPackingError",
|
||||
"null_point_separation",
|
||||
"golden_angle_pack",
|
||||
"allocator_layout_descriptor",
|
||||
"register_packed_modes",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
"""core.physics.fibonacci_search — fixed-budget Fibonacci section search (ADR-0242).
|
||||
"""core.physics.fibonacci_search — evidence-gated Fibonacci section search (ADR-0242 V1).
|
||||
|
||||
Deterministic 1D unimodal minimization for construction / calibration /
|
||||
GoldTether κ-style scalar brackets. Not a serve-path operator (A-04 quarantine).
|
||||
|
||||
Public result is always a typed ``FibonacciSearchCertificate`` or
|
||||
``OptimizationFailure`` — never a bare float (Drive evidence discipline).
|
||||
|
||||
Fail-closed on:
|
||||
* nonfinite objective values
|
||||
* invalid bounds / budget
|
||||
|
|
@ -12,9 +15,11 @@ Fail-closed on:
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Callable
|
||||
from typing import Callable, Union
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
|
|
@ -32,8 +37,65 @@ class BoundedUnimodalObjective:
|
|||
raise ValueError("upper bound must be strictly greater than lower bound")
|
||||
if not math.isfinite(self.lower) or not math.isfinite(self.upper):
|
||||
raise ValueError("bounds must be finite")
|
||||
if not str(self.objective_id).strip():
|
||||
raise ValueError("objective_id is required")
|
||||
if not str(self.objective_version).strip():
|
||||
raise ValueError("objective_version is required")
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class FibonacciSearchCertificate:
|
||||
"""Cryptographically content-addressed, replayable optimization result."""
|
||||
|
||||
minimizer: float
|
||||
final_interval: tuple[float, float]
|
||||
evaluations: int
|
||||
ordered_points: tuple[float, ...]
|
||||
ordered_values: tuple[float, ...]
|
||||
objective_id: str
|
||||
objective_version: str
|
||||
cert_id: str = field(default="")
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not self.cert_id:
|
||||
object.__setattr__(self, "cert_id", _cert_digest(self))
|
||||
|
||||
def as_dict(self) -> dict[str, object]:
|
||||
return {
|
||||
"kind": "FibonacciSearchCertificate",
|
||||
"cert_id": self.cert_id,
|
||||
"minimizer": self.minimizer,
|
||||
"final_interval": list(self.final_interval),
|
||||
"evaluations": self.evaluations,
|
||||
"ordered_points": list(self.ordered_points),
|
||||
"ordered_values": list(self.ordered_values),
|
||||
"objective_id": self.objective_id,
|
||||
"objective_version": self.objective_version,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class OptimizationFailure:
|
||||
"""Typed failure — never silently accept a candidate minimizer."""
|
||||
|
||||
reason: str
|
||||
final_interval: tuple[float, float]
|
||||
evaluations: int
|
||||
objective_id: str
|
||||
objective_version: str
|
||||
|
||||
def as_dict(self) -> dict[str, object]:
|
||||
return {
|
||||
"kind": "OptimizationFailure",
|
||||
"reason": self.reason,
|
||||
"final_interval": list(self.final_interval),
|
||||
"evaluations": self.evaluations,
|
||||
"objective_id": self.objective_id,
|
||||
"objective_version": self.objective_version,
|
||||
}
|
||||
|
||||
|
||||
# Backward-compat view (cohesion sketches). Prefer Certificate | Failure.
|
||||
@dataclass(slots=True)
|
||||
class SearchTrace:
|
||||
best_observed_point: float
|
||||
|
|
@ -41,6 +103,11 @@ class SearchTrace:
|
|||
certificate: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
SearchResult = Union[FibonacciSearchCertificate, OptimizationFailure]
|
||||
|
||||
BASELINE_KAPPA: float = 1.0
|
||||
|
||||
|
||||
def fibonacci_number(n: int) -> int:
|
||||
"""F_0=0, F_1=1, … standard Fibonacci. n may be 0."""
|
||||
if n < 0:
|
||||
|
|
@ -52,13 +119,27 @@ def fibonacci_number(n: int) -> int:
|
|||
|
||||
|
||||
def _fibonacci(n: int) -> int:
|
||||
"""Internal alias — prefer :func:`fibonacci_number` at call sites."""
|
||||
return fibonacci_number(n)
|
||||
|
||||
|
||||
def _assert_sampled_unimodality(eval_values: dict[float, float]) -> None:
|
||||
"""Fail-closed if sorted samples are not unimodal about the observed min."""
|
||||
def _cert_digest(cert: FibonacciSearchCertificate) -> str:
|
||||
payload = {
|
||||
"minimizer": cert.minimizer,
|
||||
"final_interval": list(cert.final_interval),
|
||||
"evaluations": cert.evaluations,
|
||||
"ordered_points": list(cert.ordered_points),
|
||||
"ordered_values": list(cert.ordered_values),
|
||||
"objective_id": cert.objective_id,
|
||||
"objective_version": cert.objective_version,
|
||||
}
|
||||
raw = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
return hashlib.sha256(raw).hexdigest()
|
||||
|
||||
|
||||
def _unimodality_ok(eval_values: dict[float, float]) -> bool:
|
||||
sorted_points = sorted(eval_values.keys())
|
||||
if len(sorted_points) < 2:
|
||||
return True
|
||||
min_idx = 0
|
||||
min_val = float("inf")
|
||||
for i, x in enumerate(sorted_points):
|
||||
|
|
@ -66,60 +147,119 @@ def _assert_sampled_unimodality(eval_values: dict[float, float]) -> None:
|
|||
if v < min_val:
|
||||
min_val = v
|
||||
min_idx = i
|
||||
|
||||
# Strictly non-increasing toward min (allow float ties).
|
||||
for i in range(min_idx):
|
||||
left = eval_values[sorted_points[i]]
|
||||
right = eval_values[sorted_points[i + 1]]
|
||||
if left < right - 1e-9:
|
||||
raise ValueError(
|
||||
"unimodality violation detected (multiple extrema): "
|
||||
"values not decreasing before minimum."
|
||||
)
|
||||
|
||||
# Strictly non-decreasing after min (allow float ties).
|
||||
return False
|
||||
for i in range(min_idx, len(sorted_points) - 1):
|
||||
left = eval_values[sorted_points[i]]
|
||||
right = eval_values[sorted_points[i + 1]]
|
||||
if left > right + 1e-9:
|
||||
raise ValueError(
|
||||
"unimodality violation detected (multiple extrema): "
|
||||
"values not increasing after minimum."
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _failure(
|
||||
objective: BoundedUnimodalObjective,
|
||||
*,
|
||||
reason: str,
|
||||
a: float,
|
||||
b: float,
|
||||
evaluations: int,
|
||||
) -> OptimizationFailure:
|
||||
return OptimizationFailure(
|
||||
reason=reason,
|
||||
final_interval=(float(a), float(b)),
|
||||
evaluations=int(evaluations),
|
||||
objective_id=objective.objective_id,
|
||||
objective_version=objective.objective_version,
|
||||
)
|
||||
|
||||
|
||||
def fibonacci_section_search(
|
||||
objective: BoundedUnimodalObjective,
|
||||
func: Callable[[float], float],
|
||||
) -> SearchTrace:
|
||||
"""Fibonacci section search: exactly ``evaluation_budget`` function evals.
|
||||
) -> SearchResult:
|
||||
"""Fibonacci section search with evidence-gated result.
|
||||
|
||||
Returns :class:`SearchTrace` with ``best_observed_point``, ``eval_sequence``,
|
||||
and a small certificate dict (budget, ids, bounds).
|
||||
Returns :class:`FibonacciSearchCertificate` on success or
|
||||
:class:`OptimizationFailure` on any fail-closed condition.
|
||||
Never returns a bare float.
|
||||
"""
|
||||
n = int(objective.evaluation_budget)
|
||||
a = float(objective.lower)
|
||||
b = float(objective.upper)
|
||||
a0 = float(objective.lower)
|
||||
b0 = float(objective.upper)
|
||||
a, b = a0, b0
|
||||
|
||||
if n < 2:
|
||||
return _failure(
|
||||
objective,
|
||||
reason="budget_too_low_for_unimodal_search",
|
||||
a=a0,
|
||||
b=b0,
|
||||
evaluations=0,
|
||||
)
|
||||
|
||||
f_n_plus_1 = _fibonacci(n + 1)
|
||||
f_n_minus_1 = _fibonacci(n - 1)
|
||||
f_n = _fibonacci(n)
|
||||
if f_n_plus_1 == 0:
|
||||
return _failure(
|
||||
objective,
|
||||
reason="degenerate_fibonacci_schedule",
|
||||
a=a0,
|
||||
b=b0,
|
||||
evaluations=0,
|
||||
)
|
||||
|
||||
c = a + (f_n_minus_1 / f_n_plus_1) * (b - a)
|
||||
d = a + (f_n / f_n_plus_1) * (b - a)
|
||||
|
||||
def _eval(x: float) -> float:
|
||||
points: list[float] = []
|
||||
values: list[float] = []
|
||||
eval_values: dict[float, float] = {}
|
||||
|
||||
def _eval(x: float) -> float | OptimizationFailure:
|
||||
if x < objective.lower - 1e-12 or x > objective.upper + 1e-12:
|
||||
raise ValueError(f"bounds violation: evaluated {x} outside [{objective.lower}, {objective.upper}]")
|
||||
y = float(func(x))
|
||||
return _failure(
|
||||
objective,
|
||||
reason=f"bounds_violation: evaluated {x} outside [{objective.lower}, {objective.upper}]",
|
||||
a=a,
|
||||
b=b,
|
||||
evaluations=len(points),
|
||||
)
|
||||
try:
|
||||
y = float(func(x))
|
||||
except Exception as exc: # noqa: BLE001 — typed failure surface
|
||||
return _failure(
|
||||
objective,
|
||||
reason=f"evaluation_error: {type(exc).__name__}: {exc}",
|
||||
a=a,
|
||||
b=b,
|
||||
evaluations=len(points),
|
||||
)
|
||||
if not math.isfinite(y):
|
||||
raise ValueError(f"Objective function returned nonfinite value {y} at {x}")
|
||||
return _failure(
|
||||
objective,
|
||||
reason=f"nonfinite_objective_value_at_{x}",
|
||||
a=a,
|
||||
b=b,
|
||||
evaluations=len(points),
|
||||
)
|
||||
return y
|
||||
|
||||
fc = _eval(c)
|
||||
fd = _eval(d)
|
||||
eval_sequence = [c, d]
|
||||
eval_values: dict[float, float] = {c: fc, d: fd}
|
||||
r_c = _eval(c)
|
||||
if isinstance(r_c, OptimizationFailure):
|
||||
return r_c
|
||||
r_d = _eval(d)
|
||||
if isinstance(r_d, OptimizationFailure):
|
||||
return r_d
|
||||
fc, fd = r_c, r_d
|
||||
points.extend([c, d])
|
||||
values.extend([fc, fd])
|
||||
eval_values[c] = fc
|
||||
eval_values[d] = fd
|
||||
|
||||
best_x = c if fc < fd else d
|
||||
best_f = min(fc, fd)
|
||||
|
|
@ -133,8 +273,12 @@ def fibonacci_section_search(
|
|||
f_n_minus_k_minus_1 = _fibonacci(n - k - 1)
|
||||
f_n_minus_k_plus_1 = _fibonacci(n - k + 1)
|
||||
c = a + (f_n_minus_k_minus_1 / f_n_minus_k_plus_1) * (b - a)
|
||||
fc = _eval(c)
|
||||
eval_sequence.append(c)
|
||||
r_c = _eval(c)
|
||||
if isinstance(r_c, OptimizationFailure):
|
||||
return r_c
|
||||
fc = r_c
|
||||
points.append(c)
|
||||
values.append(fc)
|
||||
eval_values[c] = fc
|
||||
if fc < best_f:
|
||||
best_f = fc
|
||||
|
|
@ -146,36 +290,88 @@ def fibonacci_section_search(
|
|||
f_n_minus_k = _fibonacci(n - k)
|
||||
f_n_minus_k_plus_1 = _fibonacci(n - k + 1)
|
||||
d = a + (f_n_minus_k / f_n_minus_k_plus_1) * (b - a)
|
||||
fd = _eval(d)
|
||||
eval_sequence.append(d)
|
||||
r_d = _eval(d)
|
||||
if isinstance(r_d, OptimizationFailure):
|
||||
return r_d
|
||||
fd = r_d
|
||||
points.append(d)
|
||||
values.append(fd)
|
||||
eval_values[d] = fd
|
||||
if fd < best_f:
|
||||
best_f = fd
|
||||
best_x = d
|
||||
k += 1
|
||||
|
||||
_assert_sampled_unimodality(eval_values)
|
||||
if not _unimodality_ok(eval_values):
|
||||
return _failure(
|
||||
objective,
|
||||
reason="unimodality_violation_multiple_extrema_detected",
|
||||
a=a,
|
||||
b=b,
|
||||
evaluations=len(points),
|
||||
)
|
||||
|
||||
certificate = {
|
||||
"budget": objective.evaluation_budget,
|
||||
"objective_id": objective.objective_id,
|
||||
"objective_version": objective.objective_version,
|
||||
"lower_bound": objective.lower,
|
||||
"upper_bound": objective.upper,
|
||||
"best_value": best_f,
|
||||
"n_evals": len(eval_sequence),
|
||||
}
|
||||
# Drive cert uses midpoint of final bracket; track also retains best sample.
|
||||
minimizer = 0.5 * (a + b)
|
||||
# Prefer best sample if it lies inside final bracket (more accurate under noise).
|
||||
if a - 1e-15 <= best_x <= b + 1e-15:
|
||||
minimizer = float(best_x)
|
||||
|
||||
return FibonacciSearchCertificate(
|
||||
minimizer=float(minimizer),
|
||||
final_interval=(float(a), float(b)),
|
||||
evaluations=len(points),
|
||||
ordered_points=tuple(float(p) for p in points),
|
||||
ordered_values=tuple(float(v) for v in values),
|
||||
objective_id=objective.objective_id,
|
||||
objective_version=objective.objective_version,
|
||||
)
|
||||
|
||||
|
||||
def propose_kappa_from_search(
|
||||
result: SearchResult,
|
||||
*,
|
||||
baseline: float = BASELINE_KAPPA,
|
||||
) -> tuple[float, SearchResult]:
|
||||
"""Evidence-gated κ: cert → minimizer; failure → baseline (default 1.0).
|
||||
|
||||
Never promotes COHERENT standing or mutates identity — caller telemetry only.
|
||||
"""
|
||||
if isinstance(result, FibonacciSearchCertificate):
|
||||
return float(result.minimizer), result
|
||||
return float(baseline), result
|
||||
|
||||
|
||||
def search_trace_from_result(result: SearchResult) -> SearchTrace:
|
||||
"""Legacy adapter for sketches that expect SearchTrace (raises on failure)."""
|
||||
if isinstance(result, OptimizationFailure):
|
||||
raise ValueError(result.reason)
|
||||
return SearchTrace(
|
||||
best_observed_point=float(best_x),
|
||||
eval_sequence=list(eval_sequence),
|
||||
certificate=certificate,
|
||||
best_observed_point=result.minimizer,
|
||||
eval_sequence=list(result.ordered_points),
|
||||
certificate={
|
||||
"budget": result.evaluations,
|
||||
"objective_id": result.objective_id,
|
||||
"objective_version": result.objective_version,
|
||||
"lower_bound": result.final_interval[0],
|
||||
"upper_bound": result.final_interval[1],
|
||||
"best_value": None,
|
||||
"n_evals": result.evaluations,
|
||||
"cert_id": result.cert_id,
|
||||
"kind": "FibonacciSearchCertificate",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"fibonacci_number",
|
||||
|
||||
"BASELINE_KAPPA",
|
||||
"BoundedUnimodalObjective",
|
||||
"FibonacciSearchCertificate",
|
||||
"OptimizationFailure",
|
||||
"SearchResult",
|
||||
"SearchTrace",
|
||||
"fibonacci_number",
|
||||
"fibonacci_section_search",
|
||||
"propose_kappa_from_search",
|
||||
"search_trace_from_result",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -521,3 +521,40 @@ class GoldTetherMonitor:
|
|||
for h in self.history[-16:]
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ADR-0242 V1 — evidence-gated κ line search (optional, off-serve)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def propose_kappa_line_search(
|
||||
residual_fn,
|
||||
*,
|
||||
lower: float = 0.1,
|
||||
upper: float = 2.0,
|
||||
evaluation_budget: int = 16,
|
||||
objective_id: str = "goldtether_kappa",
|
||||
objective_version: str = "v1",
|
||||
) -> tuple[float, object]:
|
||||
"""Optional κ search via Fibonacci section (ADR-0242 Phase 1 seam).
|
||||
|
||||
Returns ``(kappa, cert_or_failure)``. On failure, kappa is baseline 1.0.
|
||||
Does **not** mutate GoldTetherMonitor state, COHERENT standing, or serve
|
||||
autonomy — caller may record the result as telemetry only.
|
||||
"""
|
||||
from core.physics.fibonacci_search import (
|
||||
BoundedUnimodalObjective,
|
||||
fibonacci_section_search,
|
||||
propose_kappa_from_search,
|
||||
)
|
||||
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=float(lower),
|
||||
upper=float(upper),
|
||||
evaluation_budget=int(evaluation_budget),
|
||||
objective_id=str(objective_id),
|
||||
objective_version=str(objective_version),
|
||||
)
|
||||
result = fibonacci_section_search(objective, residual_fn)
|
||||
return propose_kappa_from_search(result)
|
||||
|
|
|
|||
|
|
@ -1,75 +1,124 @@
|
|||
# ADR-0242: Hyperbolic Atlas Golden-Angle Packing and Fibonacci Search
|
||||
# ADR-0242: Deterministic Fibonacci Operators and Evidence-Gated Optimization
|
||||
|
||||
**Status**: Proposed — packing + Fibonacci search + multi-scale τ schedule green; **ready for Joshua acceptance review** (do not self-Accept). Checklist: `docs/audit/adr_0241_cohesion_acceptance_checklist.md`.
|
||||
**Date**: 2026-07-14
|
||||
**Deciders**: Joshua Shay + multi-model R&D (Gemini implementation pass)
|
||||
**Traceability**: PR #37, parent ADR-0241 / cohesion master plan
|
||||
**Related**: ADR-0003, ADR-0238, ADR-0241, `docs/analysis/core_cohesion_master_plan.md`, `docs/briefs/ADR-0242-atlas-packing-and-fibonacci-brief.md`
|
||||
**Canonical path**: `docs/adr/`
|
||||
**Status**: Proposed — V1 cert discipline + V3 packing landed; V2/V4/V5 staged; **not** self-Accepted (Joshua review).
|
||||
**Date**: 2026-07-13 (Drive authority); in-repo expansion 2026-07-15
|
||||
**Deciders**: Joshua Shay + multi-model R&D
|
||||
**Traceability**: Drive ADR-0242 (`15_NECCPy-tEWGfYi_BNqawm8GytUTMkz1DsOqGVMXhI`), PR #37/#38, cohesion plan
|
||||
**Related**: ADR-0003, ADR-0238, ADR-0239, ADR-0240, ADR-0241, `docs/analysis/fibonacci_applications_in_core_substrate.md`, `docs/analysis/core_cohesion_master_plan.md`
|
||||
**Canonical path**: `docs/adr/`
|
||||
**Filename note**: file keeps historical path `ADR-0242-atlas-packing-and-fibonacci.md`; **title/scope match Drive**.
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
ADR-0241 established `WaveManifold` and `HolographicVaultStore`. Entity cohesion still needed:
|
||||
ADR-0241 establishes continuous wave-field \(\psi\). Optimization, scheduling, and multi-scale allocation still need deterministic, reconstructible operators that **earn their place** under CORE’s evidence discipline — not sacred-geometry dogma.
|
||||
|
||||
1. **Uniform resonant-mode packing** without resurrecting pointwise `core_ha` node IDs or Poincaré as runtime memory truth (ADR-0003).
|
||||
2. **Fixed-budget unimodal scalar search** for construction/calibration (e.g. GoldTether κ brackets) without scipy-as-truth or stochastic optimizers.
|
||||
Drive ADR-0242 defines **five Fibonacci vectors**. An earlier in-repo draft understated that thesis as packing + section search only. This document restores the full scope and records honest landing status.
|
||||
|
||||
## Decision
|
||||
---
|
||||
|
||||
### 1. Golden-Angle packing (`core/physics/atlas_packing.py`)
|
||||
## Sovereignty invariant (absolute)
|
||||
|
||||
For \(k = 0 \ldots n-1\):
|
||||
**Fibonacci operators may optimize search parameters, set observation scale, or schedule background checks; they must NEVER dictate proposition truth, safety policy, identity, or authorize autonomous COHERENT promotion.**
|
||||
|
||||
Active reasoning, vault standing, and serve remain governed by versor closure, CRDT exactness, and human-gated review.
|
||||
|
||||
---
|
||||
|
||||
## Decision — five vectors
|
||||
|
||||
### Vector 1 — Bounded Fibonacci-section search (production Phase 1) 🟢
|
||||
|
||||
Module: `core/physics/fibonacci_search.py`
|
||||
|
||||
- `BoundedUnimodalObjective`
|
||||
- `fibonacci_section_search(objective, func) -> FibonacciSearchCertificate | OptimizationFailure`
|
||||
- **Never** returns a bare float
|
||||
- Certificate is content-addressed (`cert_id` = SHA-256 of ordered trace + ids)
|
||||
- Fail-closed: nonfinite, bounds, unimodality multi-extrema → `OptimizationFailure`
|
||||
- κ seam: `propose_kappa_from_search` / `goldtether.propose_kappa_line_search`
|
||||
- success → proposed κ = minimizer (telemetry; no auto state mutation)
|
||||
- failure → **baseline κ = 1.0**
|
||||
|
||||
### Vector 2 — Multi-scale temporal basis (research) 🟡
|
||||
|
||||
Drive:
|
||||
|
||||
\[
|
||||
\theta_k = 2\pi k / \varphi,\qquad r_k = \tanh(\alpha\sqrt{k})
|
||||
E_n(t) = E_n(t_0)\,\exp\bigl(-(t-t_0)/(F_n\tau_0)\bigr)
|
||||
\]
|
||||
|
||||
Lift \((r\cos\theta, r\sin\theta, 0)\) via `algebra.cga.embed_point` to Cl(4,1) **null points**.
|
||||
Landed progressive form: `fibonacci_tau_schedule` / `recency_band_index` in `wave_energy_boundary.py` (constants table).
|
||||
**Not** yet production default inside `FieldEnergyOperator`. Promotion requires comparative benchmark vs dyadic \(2^n\tau_0\) (Drive comparative hypothesis).
|
||||
|
||||
**Separation pin:** CGA null-point distance from `cga_inner` contract \(\langle P,Q\rangle = -d^2/2\):
|
||||
### Vector 3 — Golden-Angle mode allocator 🟢
|
||||
|
||||
\[
|
||||
d = \sqrt{-2\langle P,Q\rangle}
|
||||
\]
|
||||
Module: `core/physics/atlas_packing.py`
|
||||
|
||||
Fail-closed (`AtlasPackingError`) if any pair has \(d < d_{\min}\) (default \(0.12\)).
|
||||
- Golden-Angle polar lift via `embed_point` → null 32-vectors
|
||||
- Fail-closed if pairwise CGA null-point \(d < d_{\min}\) (default 0.12)
|
||||
- Honest metric: Euclidean null-cone readout, **not** full \(H^2\) geodesic
|
||||
- Reconstruction-over-storage: `ALLOCATOR_VERSION = golden_angle_v1` + `allocator_layout_descriptor`
|
||||
- Not holographic seals (null points ≠ closed unit versors)
|
||||
|
||||
**Honest scope:** this \(d\) is the Euclidean distance of the embedded \(\mathbb{R}^3\) points (null-cone isometric readout), not a full hyperbolic \(H^2\) geodesic solver. Sufficient for the cohesion packing density gate.
|
||||
### Vector 4 — Fibonacci-word observability choreography 🔴 staged
|
||||
|
||||
**No attribute leaks:** returned modes are pure `float64` 32-vectors. No stored θ/r.
|
||||
Drive: \(W_0=B, W_1=A, W_{n+1}=W_n W_{n-1}\) for telemetry / sealed-holdout sampling.
|
||||
**Outside cognitive truth path.** Not yet implemented (plan D5).
|
||||
|
||||
**Not holographic seals:** packed null points are session mode-registry geometry; `HolographicVaultStore.seal_mode` still requires closed unit versors.
|
||||
### Vector 5 — Topological anyon / braid holonomy 🔴 research quarantine
|
||||
|
||||
### 2. Fibonacci section search (`core/physics/fibonacci_search.py`)
|
||||
Drive: isolated `algebra/topological_reasoning/` study; blocked from production.
|
||||
Not implemented (plan D6). Must not enter serve/FFI until proofs exist.
|
||||
|
||||
- `BoundedUnimodalObjective(lower, upper, evaluation_budget, objective_id, objective_version)`
|
||||
- `fibonacci_section_search(objective, func) -> SearchTrace`
|
||||
- Exactly `evaluation_budget` evaluations
|
||||
- Fail-closed on nonfinite, bounds violation, sampled unimodality violation
|
||||
- Certificate carries budget, ids, bounds, best value, n_evals
|
||||
---
|
||||
|
||||
### 3. Serve quarantine (A-04)
|
||||
## Phase order (Drive §5)
|
||||
|
||||
Neither module may be imported from `chat/runtime.py`. Pinned in `tests/test_third_door_cohesion.py`.
|
||||
| Phase | Vector | Status |
|
||||
|-------|--------|--------|
|
||||
| 1 | V1 search + κ cert gate | 🟢 |
|
||||
| 2 | V2 multi-scale energy study | 🟡 table only |
|
||||
| 3 | V3 packing | 🟢 |
|
||||
| 4 | V4 word scheduler | 🔴 |
|
||||
| 5 | V5 anyons | 🔴 quarantine |
|
||||
|
||||
---
|
||||
|
||||
## Serve quarantine (A-04)
|
||||
|
||||
`fibonacci_search`, `atlas_packing`, `wave_energy_boundary` must not be imported from `chat/runtime.py` (AST pin in `tests/test_third_door_cohesion.py`).
|
||||
|
||||
---
|
||||
|
||||
## Consequences
|
||||
|
||||
### Benefits
|
||||
|
||||
- Deterministic atlas packing for standing-wave mode placement
|
||||
- Algebra-native fixed-budget scalar search for κ / residual brackets
|
||||
- Continues `core_ha` deprecation (no node IDs / Poincaré runtime store)
|
||||
- Evidence-gated optimizers (typed cert/failure)
|
||||
- Deterministic packing without `core_ha` node IDs
|
||||
- Clear multi-vector roadmap without dogma
|
||||
|
||||
### Trade-offs
|
||||
|
||||
- Separation is CGA null-point Euclidean distance, not full hyperbolic geodesic
|
||||
- Unimodality check is sample-based (only evaluated points), not a global oracle
|
||||
- Packing modes are null points, not unit versors — durable vault seal path remains separate
|
||||
- Sample-based unimodality (not global oracle)
|
||||
- Packing separation not full hyperbolic geodesic
|
||||
- V2 production promotion deferred pending benchmarks
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
- `tests/test_adr_0242_atlas_packing.py`
|
||||
- `tests/test_adr_0242_fibonacci.py`
|
||||
- `tests/test_third_door_cohesion.py` (serve quarantine + κ integration)
|
||||
- `tests/test_adr_0242_fibonacci.py` — cert/failure + dual-run digest + κ fallback
|
||||
- `tests/test_adr_0242_atlas_packing.py`
|
||||
- `tests/test_third_door_cohesion.py` — serve quarantine + κ integration
|
||||
- `tests/test_adr_0241_wave_energy_boundary.py` — \(\tau_n\) table
|
||||
|
||||
---
|
||||
|
||||
## Acceptance path
|
||||
|
||||
Joshua review may Accept after Phase 1 (V1+V3) is verified in merge.
|
||||
V2/V4/V5 need not block Phase 1 Accept if status rows remain honest RESEARCH/staged.
|
||||
Agents **must not** self-Accept.
|
||||
|
|
|
|||
60
docs/analysis/fibonacci_applications_in_core_substrate.md
Normal file
60
docs/analysis/fibonacci_applications_in_core_substrate.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# R&D Memorandum: Non-Forced Applications of Fibonacci and Golden Ratio Dynamics in the CORE Substrate
|
||||
|
||||
**Status**: Proposed (Exploratory R&D / Theoretical Blueprint)
|
||||
**Date**: 2026-07-13
|
||||
**Authors**: Multi-model R&D + Joshua Shay
|
||||
**Traceability**: Drive memo `1wcuxwfxk6AW6du4SgKe4AuRxMaE5tipxG2VbrXeWM6c`
|
||||
**Related**: ADR-0003, ADR-0006, ADR-0238, ADR-0239, ADR-0241, ADR-0242, `core/physics/energy.py`, `core/physics/fibonacci_search.py`, `core/physics/atlas_packing.py`
|
||||
**Canonical path**: `docs/analysis/fibonacci_applications_in_core_substrate.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
In natural systems, the Fibonacci sequence \(F_n = F_{n-1}+F_{n-2}\) and Golden Ratio \(\varphi = (1+\sqrt{5})/2\) appear in optimal packing and multi-scale structure. CORE does **not** force sacred geometry. Operators land only where they provide deterministic, reconstructible, evidence-gated advantage (ADR-0242 sovereignty invariant).
|
||||
|
||||
## 2. Four integration vectors (memo) ↔ ADR-0242 five vectors
|
||||
|
||||
| Memo § | Topic | ADR-0242 vector | Landing status |
|
||||
|--------|-------|-----------------|----------------|
|
||||
| 2.1 | Hyperbolic golden-spiral mode packing | V3 | 🟢 `atlas_packing.py` |
|
||||
| 2.2 | Fibonacci anyons / braid holonomy | V5 | 🔴 research only |
|
||||
| 2.3 | Fibonacci-section search | V1 | 🟢 cert-gated `fibonacci_search.py` |
|
||||
| §4 | Multi-scale \(\tau_n = F_n\tau_0\) energy | V2 | 🟡 table in `wave_energy_boundary`; not production default |
|
||||
| (Drive add) | Fibonacci-word observability schedule | V4 | 🔴 staged |
|
||||
|
||||
### 2.1 Optimal spectral mode packing (V3)
|
||||
|
||||
Place mode centroids via Golden Angle / phyllotaxis and lift to Cl(4,1) null points. Separation pin \(d_{\min}\) uses CGA null-point distance (honest Euclidean readout). See ADR-0242 V3.
|
||||
|
||||
### 2.2 Fibonacci anyons (V5 — research)
|
||||
|
||||
Fusion \(\tau\otimes\tau = \mathbf{1}\oplus\tau\) as a topological composition research program. **Blocked from production** until algebraic + numerical proofs exist. Do not wire into serve, vault COHERENT, or FFI.
|
||||
|
||||
### 2.3 Fibonacci-section search (V1)
|
||||
|
||||
Fixed-budget unimodal search for κ / residual brackets. Public API returns `FibonacciSearchCertificate | OptimizationFailure` only. κ failure → baseline 1.0.
|
||||
|
||||
### 2.4 Multi-scale temporal windows (V2)
|
||||
|
||||
\[
|
||||
\tau_n = F_n\cdot\tau_0
|
||||
\quad\Rightarrow\quad
|
||||
\{1,1,2,3,5,8,13,\ldots\}\tau_0
|
||||
\]
|
||||
|
||||
Progressive landing: constants schedule + band index. Production `FieldEnergyOperator` multi-band \(E_n(t)\) requires comparative evidence vs dyadic bases (ADR-0242 Phase 2).
|
||||
|
||||
## 3. Engineering guidelines
|
||||
|
||||
- **No force-fitting** — elegance is not acceptance.
|
||||
- **Evidence gate** — certificates / failures, not silent floats.
|
||||
- **Off-serve** — fibonacci / packing / energy-boundary modules quarantined from `chat/runtime.py`.
|
||||
- **Reconstruction-over-storage** for packing layout identity.
|
||||
|
||||
## 4. Cross-links
|
||||
|
||||
- ADR-0242 (authoritative five-vector decision record)
|
||||
- ADR-0241 wave-field substrate
|
||||
- Cohesion master plan entity traces
|
||||
- Fidelity ledger §12
|
||||
|
|
@ -299,8 +299,12 @@ PY
|
|||
| Serve path not wired to wave / Fibonacci (containment) | 🟢 (AST-pinned in cohesion suite; includes `wave_seam`) |
|
||||
| Entity I-01…I-05 cohesion suite | 🟢 progressive pins in `test_third_door_cohesion.py` (I-02 float32-honest) |
|
||||
| Vault public `get_versor` ABI | 🟢 |
|
||||
| Golden-Angle atlas packing \(d_{\min}=0.12\) | 🟢 ADR-0242 (`atlas_packing`; CGA null-point \(d\)) |
|
||||
| Fibonacci κ search | 🟢 ADR-0242 (`fibonacci_search`) |
|
||||
| Golden-Angle atlas packing \(d_{\min}=0.12\) (V3) | 🟢 ADR-0242 (`atlas_packing`; CGA null-point \(d\); `golden_angle_v1`) |
|
||||
| Fibonacci section search cert/failure (V1) | 🟢 ADR-0242 (`FibonacciSearchCertificate` \| `OptimizationFailure`; dual-run digest) |
|
||||
| κ cert gate fail → baseline 1.0 (V1b) | 🟢 `propose_kappa_from_search` / `goldtether.propose_kappa_line_search` |
|
||||
| Multi-scale \(\tau_n=F_n\tau_0\) (V2) | 🟡 table only; production multi-band \(E_n(t)\) not default |
|
||||
| Fibonacci-word scheduler (V4) | 🔴 staged |
|
||||
| Fibonacci anyons (V5) | 🔴 research quarantine |
|
||||
| Contemplation Trace A SPECULATIVE holographic seal (P9) | 🟢 `core/contemplation/wave_seam.py` (hypothesis vs COHERENT evidence) |
|
||||
| Energy boundary + multi-scale τ (P10 Trace B) | 🟢 `wave_energy_boundary` (wave residual → energy/trajectory; τ_n=F_n·τ_0; E0–E1 crystallization) |
|
||||
|
||||
|
|
@ -339,7 +343,7 @@ PY
|
|||
| Durable holographic vault spectrum — 🟢 HolographicVaultStore | ADR-0241 |
|
||||
| Contemplation Trace A SPECULATIVE seal (P9) — 🟢 wave_seam | ADR-0241 P9 |
|
||||
| Energy boundary + multi-scale τ (P10) — 🟢 wave_energy_boundary | ADR-0241 P10 |
|
||||
| Atlas packing + Fibonacci κ (ADR-0242) — 🟢 packing + search | ADR-0242 |
|
||||
| Governance close (P12) — 🟢 contracts + checklist + ready-for-accept | ADR-0241 P12 |
|
||||
| Atlas packing + Fibonacci V1 cert (ADR-0242) — 🟢 V1/V3; V2–V5 staged | ADR-0242 Drive five-vector |
|
||||
| Governance close (P12) — 🟢 contracts + checklist | ADR-0241 P12 |
|
||||
|
||||
Closing a gap = flip its `xfail` in `tests/test_third_door_blueprint_fidelity.py` (or the ADR-0241 / cohesion suite) to a passing behavioral test and delete the matching characterization lock. That is the definition of "done right" here.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
"""ADR-0242 — Fibonacci section search behavioral pins."""
|
||||
"""ADR-0242 V1 — evidence-gated Fibonacci section search."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from core.physics.fibonacci_search import (
|
||||
BASELINE_KAPPA,
|
||||
BoundedUnimodalObjective,
|
||||
FibonacciSearchCertificate,
|
||||
OptimizationFailure,
|
||||
fibonacci_section_search,
|
||||
propose_kappa_from_search,
|
||||
)
|
||||
|
||||
|
||||
def test_fibonacci_search_hits_known_unimodal_min_within_1e_3():
|
||||
def test_fibonacci_search_returns_certificate_near_known_min():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=0.1,
|
||||
upper=2.0,
|
||||
|
|
@ -22,9 +24,34 @@ def test_fibonacci_search_hits_known_unimodal_min_within_1e_3():
|
|||
def func(x: float) -> float:
|
||||
return (x - 0.789) ** 2
|
||||
|
||||
trace = fibonacci_section_search(objective, func)
|
||||
assert abs(trace.best_observed_point - 0.789) < 1e-3
|
||||
assert len(trace.eval_sequence) == 20
|
||||
result = fibonacci_section_search(objective, func)
|
||||
assert isinstance(result, FibonacciSearchCertificate)
|
||||
assert abs(result.minimizer - 0.789) < 1e-3
|
||||
assert result.evaluations == 20
|
||||
assert len(result.ordered_points) == 20
|
||||
assert len(result.ordered_values) == 20
|
||||
assert result.cert_id
|
||||
assert len(result.cert_id) == 64
|
||||
|
||||
|
||||
def test_certificate_digest_stable_dual_run():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=-5.0,
|
||||
upper=5.0,
|
||||
evaluation_budget=15,
|
||||
objective_id="stable",
|
||||
objective_version="v1",
|
||||
)
|
||||
|
||||
def func(x: float) -> float:
|
||||
return x**2
|
||||
|
||||
a = fibonacci_section_search(objective, func)
|
||||
b = fibonacci_section_search(objective, func)
|
||||
assert isinstance(a, FibonacciSearchCertificate)
|
||||
assert isinstance(b, FibonacciSearchCertificate)
|
||||
assert a.cert_id == b.cert_id
|
||||
assert a.as_dict() == b.as_dict()
|
||||
|
||||
|
||||
def test_fibonacci_search_eval_count_equals_budget():
|
||||
|
|
@ -39,12 +66,12 @@ def test_fibonacci_search_eval_count_equals_budget():
|
|||
def func(x: float) -> float:
|
||||
return x**2
|
||||
|
||||
trace = fibonacci_section_search(objective, func)
|
||||
assert len(trace.eval_sequence) == 15
|
||||
assert trace.certificate["n_evals"] == 15
|
||||
result = fibonacci_section_search(objective, func)
|
||||
assert isinstance(result, FibonacciSearchCertificate)
|
||||
assert result.evaluations == 15
|
||||
|
||||
|
||||
def test_fibonacci_search_rejects_nan_objective():
|
||||
def test_fibonacci_search_nonfinite_returns_failure():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=-1.0,
|
||||
upper=1.0,
|
||||
|
|
@ -56,11 +83,12 @@ def test_fibonacci_search_rejects_nan_objective():
|
|||
def func(x: float) -> float:
|
||||
return float("nan")
|
||||
|
||||
with pytest.raises(ValueError, match="nonfinite"):
|
||||
fibonacci_section_search(objective, func)
|
||||
result = fibonacci_section_search(objective, func)
|
||||
assert isinstance(result, OptimizationFailure)
|
||||
assert "nonfinite" in result.reason
|
||||
|
||||
|
||||
def test_fibonacci_search_unimodality_violation_fail_closed():
|
||||
def test_fibonacci_search_unimodality_returns_failure():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=-2.0,
|
||||
upper=2.0,
|
||||
|
|
@ -70,8 +98,49 @@ def test_fibonacci_search_unimodality_violation_fail_closed():
|
|||
)
|
||||
|
||||
def func(x: float) -> float:
|
||||
# Multiple extrema: x^4 - x^2
|
||||
return x**4 - x**2
|
||||
|
||||
with pytest.raises(ValueError, match="unimodality"):
|
||||
fibonacci_section_search(objective, func)
|
||||
result = fibonacci_section_search(objective, func)
|
||||
assert isinstance(result, OptimizationFailure)
|
||||
assert "unimodality" in result.reason
|
||||
|
||||
|
||||
def test_never_returns_bare_float():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=0.0,
|
||||
upper=1.0,
|
||||
evaluation_budget=8,
|
||||
objective_id="type",
|
||||
objective_version="v1",
|
||||
)
|
||||
result = fibonacci_section_search(objective, lambda x: (x - 0.3) ** 2)
|
||||
assert not isinstance(result, float)
|
||||
assert isinstance(result, (FibonacciSearchCertificate, OptimizationFailure))
|
||||
|
||||
|
||||
def test_propose_kappa_cert_uses_minimizer():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=0.1,
|
||||
upper=2.0,
|
||||
evaluation_budget=16,
|
||||
objective_id="kappa",
|
||||
objective_version="v1",
|
||||
)
|
||||
result = fibonacci_section_search(objective, lambda x: (x - 0.5) ** 2)
|
||||
kappa, outcome = propose_kappa_from_search(result)
|
||||
assert isinstance(outcome, FibonacciSearchCertificate)
|
||||
assert abs(kappa - 0.5) < 1e-2
|
||||
|
||||
|
||||
def test_propose_kappa_failure_falls_back_to_baseline():
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=-2.0,
|
||||
upper=2.0,
|
||||
evaluation_budget=10,
|
||||
objective_id="kappa_fail",
|
||||
objective_version="v1",
|
||||
)
|
||||
result = fibonacci_section_search(objective, lambda x: x**4 - x**2)
|
||||
kappa, outcome = propose_kappa_from_search(result)
|
||||
assert isinstance(outcome, OptimizationFailure)
|
||||
assert kappa == BASELINE_KAPPA
|
||||
|
|
|
|||
|
|
@ -275,12 +275,19 @@ def test_resonant_reconstruct_empty_refused():
|
|||
M.resonant_reconstruct(_closed(0.1))
|
||||
|
||||
|
||||
# --- ADR-0242 placeholder (Fibonacci not yet landed) --------------------------
|
||||
# --- ADR-0242 V1 evidence-gated Fibonacci + κ fallback ------------------------
|
||||
|
||||
|
||||
def test_fibonacci_search_goldtether_integration():
|
||||
"""Asserts Fibonacci search can optimize kappa and return a valid certificate."""
|
||||
from core.physics.fibonacci_search import BoundedUnimodalObjective, fibonacci_section_search
|
||||
"""Fibonacci search optimizes κ; cert-gated propose never silent-fails."""
|
||||
from core.physics.fibonacci_search import (
|
||||
BASELINE_KAPPA,
|
||||
BoundedUnimodalObjective,
|
||||
FibonacciSearchCertificate,
|
||||
OptimizationFailure,
|
||||
fibonacci_section_search,
|
||||
propose_kappa_from_search,
|
||||
)
|
||||
|
||||
objective = BoundedUnimodalObjective(
|
||||
lower=0.1,
|
||||
|
|
@ -293,7 +300,22 @@ def test_fibonacci_search_goldtether_integration():
|
|||
def synthetic_objective(kappa: float) -> float:
|
||||
return (kappa - 0.789) ** 2 # unimodal minimum at 0.789
|
||||
|
||||
trace = fibonacci_section_search(objective, synthetic_objective)
|
||||
assert abs(trace.best_observed_point - 0.789) < 1e-3
|
||||
assert len(trace.eval_sequence) == 20
|
||||
assert trace.certificate.get("budget") == 20
|
||||
result = fibonacci_section_search(objective, synthetic_objective)
|
||||
assert isinstance(result, FibonacciSearchCertificate)
|
||||
kappa, outcome = propose_kappa_from_search(result)
|
||||
assert isinstance(outcome, FibonacciSearchCertificate)
|
||||
assert abs(kappa - 0.789) < 1e-3
|
||||
assert outcome.evaluations == 20
|
||||
|
||||
# Failure path: multi-extrema → baseline κ=1.0 (Drive Phase 1).
|
||||
fail_obj = BoundedUnimodalObjective(
|
||||
lower=-2.0,
|
||||
upper=2.0,
|
||||
evaluation_budget=10,
|
||||
objective_id="kappa_fail",
|
||||
objective_version="v1.0",
|
||||
)
|
||||
fail = fibonacci_section_search(fail_obj, lambda x: x**4 - x**2)
|
||||
k_fail, out_fail = propose_kappa_from_search(fail)
|
||||
assert isinstance(out_fail, OptimizationFailure)
|
||||
assert k_fail == BASELINE_KAPPA
|
||||
|
|
|
|||
Loading…
Reference in a new issue