#[non_exhaustive]pub struct ScaleProof {Show 17 fields
pub tolerance_policy: ScaleTolerancePolicy,
pub rest_translation: ScaleProofResidual,
pub rest_rotation: ScaleProofResidual,
pub unit_scale: ScaleProofResidual,
pub transform_only_affine: ScaleProofResidual,
pub track_value: ScaleProofResidual,
pub mesh_position: ScaleProofResidual,
pub key_translation: ScaleProofResidual,
pub cubic_interior: ScaleProofResidual,
pub trajectory: ScaleProofResidual,
pub skin_matrix: ScaleProofResidual,
pub bounds: ScaleProofResidual,
pub unaffected_inverse_bind: ScaleProofResidual,
pub observed_factor: f64,
pub planned_observed_factor: f64,
pub observed_factor_divergence: f64,
pub sample_time_count: usize,
}Expand description
Observed residual maxima from prove_scale, reported against
ScalePlan::tolerance_policy, each paired with the number of
comparisons that produced it.
Read the paired value, not just its maximum. A maximum alone cannot
distinguish “compared, no deviation” from “nothing to compare”: both read
0.0, because every maximum starts there and is raised only by a loop
that may have zero iterations. So a field for an obligation the plan does
not require (see ScaleProofObligation) reports a
ScaleProofResidual whose maximum and count are both zero. A 0.0
maximum with a count above zero is a measurement; a zero count is an
absence, which DESIGN.md Appendix D §D.6 requires an evidence record to
publish as an absence rather than as a checked zero.
The counts are measurements, not proxies derived from obligation presence:
each is stored with its maximum by the single private recording method
every comparison in prove_scale funnels through. The pair’s fields are
private, so no producer can combine one claim’s count with another claim’s
maximum.
No comparison can raise a residual without being counted, and
no count can rise without a comparison having been checked against the
tolerance policy. A ScaleProofObligation may declare a proof walk, or
name a row-driven claim discharged through the canonical field inventory;
neither role substitutes for the comparison count recorded here.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.tolerance_policy: ScaleTolerancePolicyThe tolerance policy every residual below was checked against.
rest_translation: ScaleProofResidualMaximum rest-world translation residual, with one comparison per affected node.
rest_rotation: ScaleProofResidualMaximum rest-world rotation residual, in radians, directly comparable
to ScaleTolerancePolicy::rotation_residual_radians.
Measured as a double-cover-aware quaternion chord length
|q1 - q2| = 2 * sin(theta / 4) and reported as the angle
theta = 4 * asin(chord / 2) that chord represents, so this value and
the tolerance it is checked against carry the same unit.
Its count is one per affected node.
unit_scale: ScaleProofResidualMaximum postcondition unit-scale residual, with one comparison per affected node when the rest/bind plan declares the postcondition.
transform_only_affine: ScaleProofResidualMaximum transform-only attachment full-affine residual (rest/bind only), with one probe-point comparison per attachment.
track_value: ScaleProofResidualMaximum per-element animation-track value residual, across rewritten translation elements and every retained rotation/scale element. Its count is one per track element across every clip.
mesh_position: ScaleProofResidualMaximum per-vertex base mesh POSITION residual, with one comparison
per vertex.
key_translation: ScaleProofResidualMaximum residual at any affected-track keyframe time, with one comparison per affected translation track per key time.
cubic_interior: ScaleProofResidualMaximum residual at any bounded cubic-segment interior time, with one comparison per affected translation track per interior time.
trajectory: ScaleProofResidualMaximum sampled world-space trajectory residual, with one comparison per affected node per sample time.
skin_matrix: ScaleProofResidualMaximum skin-matrix (W * B) component residual, across rest and
every sampled key/cubic-interior time. Its count is one per skin slot
of every affected skinned instance at each evaluated pose.
bounds: ScaleProofResidualMaximum skinned mesh bounds residual, across rest and every sampled key/cubic-interior time. Its count is six per evaluated pose.
unaffected_inverse_bind: ScaleProofResidualMaximum stored inverse-bind residual over every skin slot outside the
affected closure (see ProofResidualKind::UnaffectedInverseBind).
Its count is one per stored slot compared outside the closure and zero
unless the plan declares
ScaleProofObligation::UnaffectedInverseBinds.
observed_factor: f64The operation’s observed factor, re-derived by this proof from the
documents it was handed rather than copied from
ScalePlan::observed_factor, so evidence does not depend on
planning having recorded it.
Reported, not checked. This is a measurement, not an obligation:
nothing here compares it against ScalePlan::common_factor. The
declared/observed agreement is the input contract §D.1 states, and
planning already enforces it (ScaleError::FactorMismatch); what
binds the candidate is the postcondition
(ProofResidualKind::UnitScale) that §D.1 derives from that band.
Measured from source, not from candidate. That is a choice, not an
impossibility: a rest/bind candidate does record what its source
measured. build_rest_bind rebases an affected node’s local scale by
s_parent / s_node with s_node the declared factor, and the
affected closure never contains the scaled root’s parent, so s_parent
is one there and the candidate’s composed root scale is exactly
s_observed / s_declared — unit only when the two agree, which the
input band admits without requiring. The candidate route is real and it
is accurate: plan.common_factor() * average_affine_axis_length( affine_axis_lengths(candidate root world linear)) recovers the
measurement to a relative error below 2^-24, the half-ulp of the one
binary32 rounding that round trip costs at unit magnitude. Swept over
all 215 binary32 values
the 1e-5 band admits around a declared 0.01, the worst is
5.9604613e-8; over this module’s own 0.01-factor fixtures it is
4.84e-8, at a source root of 0.010_000_099.
It is not the route taken, for four reasons:
- Independence.
prove_scaledoes not requirecandidateto have come from reference construction; checking one that did not is the reason it exists. Reading the reported measurement off the artifact under test would let that artifact pick its own evidence value. The observed factor is a fact about the input, so the input is where it is measured. - Precision. The candidate route divides by the declared factor in
f32and multiplies back inf64, so it reports a rounded neighbour of the source measurement rather than the measurement. - Sign. The nearest already-published proxy,
Self::unit_scale’smax(), is an absolute value, socommon_factor * (1 + unit_scale.max())reconstructss_observedonly when the observed factor is the larger of the two and reflects it about the declared factor when it is not. - Attribution. That residual is also a maximum over every affected node rather than a value read at the scaled root, so it does not name the node §D.6 defines the observed factor at.
See ScalePlan::observed_factor for how each operation defines it;
for a whole-document conversion this is the declared factor, there
being nothing to measure — and there the candidate route genuinely
does not exist, because build_whole_document rewrites translations
only and leaves every composed scale exactly as it found it.
planned_observed_factor: f64The observed factor super::plan_scale measured, copied from
ScalePlan::observed_factor.
The record carries both witnesses because they are measured from
genuinely different state and neither is derivable from the other:
this one from the raw source projection (SourceNodeAsset::local_rest
composed through parent_source_node_index),
Self::observed_factor from the normalized skeleton (Bone::rest
composed through world_rest_matrices). That independence is the
property DESIGN.md Appendix D §D.6 wants of a second witness, and it
is why the two are generally not equal. Carrying only one of them
would leave a reader unable to tell which was reported; carrying both
with no stated relationship would leave them unable to tell which to
trust, which is what Self::observed_factor_divergence answers.
For ScaleOperation::WholeDocumentLinearUnits both are the declared
factor, there being nothing to measure, and the divergence is exactly
zero.
observed_factor_divergence: f64How far apart the two observed factors are:
abs(planned - proved) / max(abs(planned), abs(proved)).
Recorded explicitly rather than left for a consumer to compute, so the
evidence record states the relationship between its own two witnesses
instead of presenting two numbers that both answer to “the observed
factor”. Compare it against
ScaleTolerancePolicy::observed_factor_divergence_ceiling, which is
how far apart the design expects them to be and why — a consumer does
not have to re-derive that ceiling by summing two separate policy
fields.
Reported, not checked. Nothing refuses a document for exceeding
the ceiling; see that method for what the ceiling does and does not
guarantee. The two chains the witnesses compose through are already
required to agree: under
crate::model::SourceSkeletonCoverage::Complete coverage a document
whose projection and skeleton describe different trees is refused
before either witness is taken. What nothing reconciles is the two
readings — crate::model::SourceNodeAsset::local_rest and
crate::model::Bone::rest stay separately stored and separately
composed, which is why both witnesses exist at all. A divergence
beyond the ceiling is therefore a fact about how far apart the input’s
two stored descriptions of one rest pose are, worth surfacing, not a
residual this proof owns.
sample_time_count: usizeNumber of distinct times sampled across all clips.
Trait Implementations§
Source§impl Clone for ScaleProof
impl Clone for ScaleProof
Source§fn clone(&self) -> ScaleProof
fn clone(&self) -> ScaleProof
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more