优化流程
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from copy import deepcopy
|
||||
from math import atan2, isclose, pi, sqrt
|
||||
from typing import Any, Callable
|
||||
|
||||
@@ -12,6 +13,7 @@ from jsonschema.exceptions import SchemaError
|
||||
|
||||
ClaimResult = dict[str, Any]
|
||||
ClaimEvaluator = Callable[[dict[str, Any], dict[str, Any]], ClaimResult]
|
||||
_DEFAULT_TOLERANCE_MM = 0.1
|
||||
|
||||
|
||||
def _closed_object(properties: dict[str, Any], required: list[str]) -> dict[str, Any]:
|
||||
@@ -49,7 +51,13 @@ def _cylinder_axis_span(record: dict[str, Any]) -> float | None:
|
||||
|
||||
|
||||
def _cylinder_axis_interval(record: dict[str, Any]) -> tuple[float, float] | None:
|
||||
"""Return the inclusive axial interval of a cylindrical face's bounds."""
|
||||
"""Return the inclusive axial interval of a cylindrical face's bounds.
|
||||
|
||||
B-rep face orientation is not a physical property of a cylindrical shell.
|
||||
In particular, a two-sided extrusion can return its two half-walls with
|
||||
opposite axis directions. Use one canonical direction for an undirected
|
||||
cylinder axis so those halves share the same coordinate interval.
|
||||
"""
|
||||
geometry = record.get("geometry") if isinstance(record.get("geometry"), dict) else {}
|
||||
bbox = geometry.get("bbox_mm")
|
||||
direction = _cylinder_axis_direction(record)
|
||||
@@ -60,6 +68,9 @@ def _cylinder_axis_interval(record: dict[str, Any]) -> tuple[float, float] | Non
|
||||
maximum = tuple(float(value) for value in bbox[3:])
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
dominant_index = max(range(3), key=lambda index: abs(direction[index]))
|
||||
if direction[dominant_index] < 0:
|
||||
direction = tuple(-component for component in direction)
|
||||
projections = [
|
||||
sum(direction[index] * point[index] for index in range(3))
|
||||
for point in (
|
||||
@@ -418,7 +429,7 @@ def _outer_cylindrical_surface(expected: dict[str, Any], facts: dict[str, Any])
|
||||
max(interval[1] for interval in shell_intervals if interval is not None)
|
||||
- min(interval[0] for interval in shell_intervals if interval is not None)
|
||||
)
|
||||
tolerance = float(expected["tolerance_mm"])
|
||||
tolerance = float(expected.get("tolerance_mm", _DEFAULT_TOLERANCE_MM))
|
||||
evidence.update({"axial_spans_mm": actual_spans, "tolerance_mm": tolerance})
|
||||
return _pass(evidence) if all(abs(span - float(axial_span)) <= tolerance for span in actual_spans) else _fail({"diameter_mm": expected["diameter_mm"], "expected_axial_span_mm": axial_span, "actual_axial_spans_mm": actual_spans, "tolerance_mm": tolerance})
|
||||
|
||||
@@ -790,11 +801,13 @@ class VerifierRegistry:
|
||||
except KeyError as error:
|
||||
raise ValueError(f"VERIFIER_UNAVAILABLE: {claim_kind}") from error
|
||||
|
||||
def expected_one_of_schema(self) -> dict[str, Any]:
|
||||
def expected_one_of_schema(self, *, exclude_claim_kinds: set[str] | frozenset[str] | tuple[str, ...] = ()) -> dict[str, Any]:
|
||||
excluded = set(exclude_claim_kinds)
|
||||
return {
|
||||
"oneOf": [
|
||||
_closed_object({"claim_kind": {"const": item.claim_kind}, "expected": item.expected_schema}, ["claim_kind", "expected"])
|
||||
for item in self._definitions.values()
|
||||
if item.claim_kind not in excluded
|
||||
]
|
||||
}
|
||||
|
||||
@@ -806,6 +819,19 @@ class VerifierRegistry:
|
||||
for error in sorted(validator.iter_errors(expected), key=lambda item: (list(item.absolute_path), item.message))
|
||||
]
|
||||
|
||||
def normalize_expected(self, claim_kind: str, expected: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Apply protocol defaults before a compiled contract is frozen.
|
||||
|
||||
These defaults describe verifier mechanics, never user geometry. The
|
||||
outer-cylinder verifier can match a diameter without a tolerance, but
|
||||
measuring its optional axial span needs one. Persist the default so
|
||||
the resulting contract is complete and independently reproducible.
|
||||
"""
|
||||
normalized = deepcopy(expected)
|
||||
if claim_kind == "outer_cylindrical_surface" and "axial_span_mm" in normalized:
|
||||
normalized.setdefault("tolerance_mm", _DEFAULT_TOLERANCE_MM)
|
||||
return normalized
|
||||
|
||||
def evaluate(self, claim_kind: str, expected: dict[str, Any], facts: dict[str, Any]) -> ClaimResult:
|
||||
errors = self.validate_expected(claim_kind, expected)
|
||||
if errors:
|
||||
|
||||
Reference in New Issue
Block a user