( body: Expression | undefined, indexes: ReadonlyArray<Expression>, ce: ComputeEngine )
| 63 | export function isTupleTypedOperand(d: OperandDescriptor): boolean { |
| 64 | return isTupleShapedType(d.type); |
| 65 | } |
| 66 | |
| 67 | /** |
| 68 | * Does this point operand carry a component that is itself an indexed |
| 69 | * collection, so that the norm zips into one result per element? |
| 70 | * |
| 71 | * `‖(x+[0.5, 1], y)‖` is one norm per element, so the honest type is |
| 72 | * `list<number>`, not `number` (Tycho item 74: a `number`-typed expression |
| 73 | * evaluating to a `List` breaks consumers that dispatch on the declared type). |
| 74 | * |
| 75 | * A tuple-typed component is NOT a broadcasting collection (tuples are indexed |
| 76 | * collections in the type lattice but bind atomically): the norm of |
| 77 | * `((3,4), 12)` takes the inner point's norm and stays scalar. |
| 78 | * |
| 79 | * A point that is not written out (a tuple-TYPED symbol or parameter) has no |
| 80 | * components to walk — its declared element types are inspected instead, so |
| 81 | * `p: tuple<list<real>, real>` reports the same broadcast its evaluation |
| 82 | * produces. |
| 83 | */ |
| 84 | export function pointNormBroadcasts(d: OperandDescriptor): boolean { |
| 85 | const children = operandChildren(d); |
| 86 | if (children !== undefined) |
| 87 | return children.some( |
| 88 | (c) => |
| 89 | isSubtype(c.type, INDEXED_COLLECTION_SHAPE_TYPE) && |
| 90 | !isTupleTypedOperand(c) |
| 91 | ); |
| 92 | const t = d.type; |
| 93 | return ( |
| 94 | typeof t !== 'string' && |
| 95 | t.kind === 'tuple' && |
| 96 | t.elements.some((el) => { |
| 97 | const et = el.type; |
| 98 | if (typeof et !== 'string' && et.kind === 'tuple') return false; |
| 99 | return isSubtype(et, INDEXED_COLLECTION_SHAPE_TYPE); |
| 100 | }) |
| 101 | ); |
| 102 | } |
| 103 | |
| 104 | /** |
| 105 | * The result type of a Euclidean norm/distance over `components` — the scalar |
| 106 | * `√(Σ|xᵢ|²)`. |
| 107 | * |
| 108 | * **A norm is REAL whatever its components are**: `|z|²` is real for a complex |
| 109 | * `z`, so `‖(3+4i, 0)‖ = 5`. Claiming the wide `number` (which includes |
| 110 | * complex) instead is not merely imprecise — it is refused by every |
| 111 | * `real`-declared slot in the library, so `Hypot(‖p‖, ‖q‖)` reported |
| 112 | * `incompatible-type('real', 'number')` on a value real by construction. |
| 113 | * |
| 114 | * The claim demands PROVEN finiteness of every component, because `real` |
no test coverage detected