Generated from the full canonical file for this source snapshot. Line numbers match the library source.
Source SHA256: 89ad54c669069b2869f1870295ae244d3979e5eed8d90ec3246aa0a1ff7c946a
1"""Fused objective/seed evaluation with a fixed FP64 reduction tree.23The image-space derivative is caller-owned. Only one scalar partial per tile is4retained: no per-pixel loss image or global floating-point atomic is needed.5"""67# Warp annotations are executable DSL expressions; host interfaces remain strict.8# The optional GPU import is resolved only when an operator is prepared.9# pyright: reportInvalidTypeForm=false, reportUnknownParameterType=false10# pyright: reportUnknownMemberType=false, reportUnknownArgumentType=false11# pyright: reportUnknownVariableType=false, reportUntypedFunctionDecorator=false12# pyright: reportMissingImports=false, reportUntypedClassDecorator=false1314from functools import cache1516import warp as wp1718TILE = 25619OPTIONS = {"fast_math": False, "fuse_fp": True, "enable_backward": False}202122@wp.func_native("return log1p(x);")23def log_one_plus(x: wp.float64) -> wp.float64: ...242526@cache27def observation_validation_kernel(poisson: bool, weighted: bool, masked: bool = False):28@wp.kernel(module="unique", module_options=OPTIONS)29def validate(30observation: wp.array(dtype=wp.float32),31weights: wp.array(dtype=wp.float32),32valid: wp.array(dtype=wp.uint8),33status: wp.array(dtype=wp.int32),34):35p = wp.tid()36active = bool(True) # noqa: UP018 - Warp runtime Boolean.37if wp.static(masked):38if valid[p] > wp.uint8(1):39wp.atomic_or(status, 0, 1)40active = valid[p] == wp.uint8(1)41if active:42value = observation[p]43invalid = not wp.isfinite(value)44if wp.static(poisson):45invalid = invalid or value < 0.0 or wp.floor(value) != value46if wp.static(weighted):47invalid = invalid or not wp.isfinite(weights[p]) or weights[p] < 0.048if invalid:49wp.atomic_or(status, 0, 1)5051return validate525354@cache55def validation_kernel(56poisson: bool, weighted: bool, masked: bool = False, precision: str = "float32"57):58value_dtype = wp.float64 if precision == "float64" else wp.float325960@wp.kernel(module="unique", module_options=OPTIONS)61def validate(62prediction: wp.array(dtype=value_dtype),63observation: wp.array(dtype=wp.float32),64weights: wp.array(dtype=wp.float32),65valid: wp.array(dtype=wp.uint8),66status: wp.array(dtype=wp.int32),67):68p = wp.tid()69active = bool(True) # noqa: UP018 - Warp runtime Boolean.70if wp.static(masked):71if valid[p] > wp.uint8(1):72wp.atomic_or(status, 0, 1)73active = valid[p] == wp.uint8(1)74if active:75a, b = prediction[p], observation[p]76invalid = not wp.isfinite(a) or not wp.isfinite(b)77if wp.static(poisson):78invalid = invalid or a < 0.0 or b < 0.0 or wp.floor(b) != b79invalid = invalid or (a == 0.0 and b > 0.0)80if wp.static(weighted):81invalid = invalid or not wp.isfinite(weights[p]) or weights[p] < 0.082if invalid:83wp.atomic_or(status, 0, 1)8485return validate868788@wp.func89def poisson_half_deviance(predicted: wp.float64, observed: wp.float64) -> wp.float64:90"""Canonical cancellation-safe Poisson term shared by both compositions."""91if observed == wp.float64(0.0):92return predicted93difference = predicted - observed94loss = wp.float64(0.0)95# Half-deviance differs from the negative log likelihood96# only by observation constants. This form retains a small97# residual near equality without evaluating log(0) for y=0.98if wp.abs(difference) <= wp.float64(0.25) * observed:99ratio = difference / observed100if wp.abs(ratio) < wp.float64(0.001):101# r-log1p(r) also cancels. Through degree six the102# omitted relative term is < 3e-16 for |r|<1e-3.103series = wp.float64(0.5) + ratio * (104(-wp.float64(1.0) / wp.float64(3.0))105+ ratio106* (107wp.float64(0.25)108+ ratio * (wp.float64(-0.2) + ratio * (wp.float64(1.0) / wp.float64(6.0)))109)110)111loss = observed * ratio * ratio * series112else:113loss = observed * (ratio - log_one_plus(ratio))114else:115loss = difference + observed * (wp.log(observed) - wp.log(predicted))116return loss117118119# region book:objective-loss-and-seed120@cache121def evaluation_kernel(122poisson: bool,123weighted: bool,124gradient: bool,125masked: bool = False,126precision: str = "float32",127):128value_dtype = wp.float64 if precision == "float64" else wp.float32129130@wp.kernel(module="unique", module_options=OPTIONS)131def evaluate(132prediction: wp.array(dtype=value_dtype),133observation: wp.array(dtype=wp.float32),134weights: wp.array(dtype=wp.float32),135valid: wp.array(dtype=wp.uint8),136size: int,137normalisation: wp.float64,138seed: wp.array(dtype=value_dtype),139partials: wp.array(dtype=wp.float64),140status: wp.array(dtype=wp.int32),141):142block, lane = wp.tid()143p = block * TILE + lane144loss = wp.float64(0.0)145if p < size:146active = bool(True) # noqa: UP018 - Warp runtime Boolean.147if wp.static(masked):148if valid[p] > wp.uint8(1):149wp.atomic_or(status, 0, 1)150active = valid[p] == wp.uint8(1)151if active:152predicted = wp.float64(prediction[p])153observed = wp.float64(observation[p])154weight = normalisation155if wp.static(weighted):156weight *= wp.float64(weights[p])157difference = predicted - observed158derivative = difference159loss = wp.float64(0.5) * difference * difference160if wp.static(poisson):161if observed == wp.float64(0.0):162loss = predicted163derivative = wp.float64(1.0)164else:165derivative = difference / predicted166loss = poisson_half_deviance(predicted, observed)167if wp.static(precision == "float64" and not poisson):168# A small fixed weight can keep the final squared loss169# representable even when the unweighted square overflows.170loss = (wp.float64(0.5) * weight * difference) * difference171else:172loss *= weight173if not wp.isfinite(loss):174wp.atomic_or(status, 0, 2)175if wp.static(gradient):176weighted_derivative = weight * derivative177if wp.static(precision == "float64" and poisson):178if not wp.isfinite(derivative):179# FP32 observations/weights bound this numerator;180# do not overflow a removable unweighted quotient.181weighted_derivative = (weight * difference) / predicted182result = value_dtype(weighted_derivative)183seed[p] = result184if not wp.isfinite(result):185wp.atomic_or(status, 0, 2)186elif wp.static(gradient):187seed[p] = value_dtype(0.0)188total = wp.tile_sum(wp.tile(loss))189wp.tile_store(partials, total, offset=block)190191return evaluate192193194# endregion book:objective-loss-and-seed195196197@cache198def primary_evaluation_kernel(poisson: bool, counts: bool, weighted: bool, masked: bool):199"""Retain the primary signal and depth cotangent in FP64 for pose fitting."""200201@wp.kernel(module="unique", module_options=OPTIONS)202def evaluate(203depth: wp.array(dtype=wp.float64),204beam: wp.float64,205observation: wp.array(dtype=wp.float32),206weights: wp.array(dtype=wp.float32),207valid: wp.array(dtype=wp.uint8),208size: int,209normalisation: wp.float64,210prediction: wp.array(dtype=wp.float64),211depth_seed: wp.array(dtype=wp.float64),212partials: wp.array(dtype=wp.float64),213status: wp.array(dtype=wp.int32),214):215block, lane = wp.tid()216p = block * TILE + lane217loss = wp.float64(0.0)218if p < size:219optical = depth[p]220predicted = -optical221if wp.static(counts):222predicted = beam * wp.exp(-optical)223if optical > wp.float64(700.0) and beam > wp.float64(0.0):224# Combine exponents before a tiny transmission can underflow.225# Keep the direct product in the ordinary near-equality range.226predicted = wp.exp(wp.log(beam) - optical)227prediction[p] = predicted228if not wp.isfinite(optical) or optical < wp.float64(0.0) or not wp.isfinite(predicted):229wp.atomic_or(status, 0, 2)230active = bool(True) # noqa: UP018 - Warp runtime Boolean.231if wp.static(masked):232if valid[p] > wp.uint8(1):233wp.atomic_or(status, 0, 1)234active = valid[p] == wp.uint8(1)235derivative = wp.float64(0.0)236if active:237observed = wp.float64(observation[p])238difference = predicted - observed239loss = wp.float64(0.5) * difference * difference240derivative = -difference241if wp.static(counts):242derivative *= predicted243if wp.static(poisson):244if predicted == wp.float64(0.0) and observed > wp.float64(0.0):245wp.atomic_or(status, 0, 2)246loss = poisson_half_deviance(predicted, observed)247if (248observed > wp.float64(0.0)249and wp.abs(difference) > wp.float64(0.25) * observed250):251# Avoid taking log of a rounded subnormal count.252loss = difference + observed * (wp.log(observed) - wp.log(beam) + optical)253# Compose (1-N/lambda)*(-lambda) before rounding/division.254derivative = -difference255weight = normalisation256if wp.static(weighted):257weight *= wp.float64(weights[p])258loss *= weight259derivative *= weight260depth_seed[p] = derivative261if not wp.isfinite(loss) or not wp.isfinite(derivative):262wp.atomic_or(status, 0, 2)263wp.tile_store(partials, wp.tile_sum(wp.tile(loss)), offset=block)264265return evaluate266