Skip to content

The tf.shape summary is a fresh Tensor allocation with no generator, so the factory refuses it at seeding and its result reads "not a tensor" (3760 refusals in the test module); a subscript of it inherits that #943

Description

@khatchad

The summary of tf.shape(x) is a fresh Tensor allocation with no generator, and a fresh allocation the factory refuses at seeding is never seeded, so its result reads ⊥ in the dataflow: this lattice's spelling of "not a tensor". Everything read from it inherits that, and a subscript of it, tf.shape(x)[0], the ordinary way a program obtains a batch or node count as a scalar tensor, reads "not a tensor" at the parameter it is passed to. Measured, with the count that makes it the subject rather than one of a class.

Measured

A probe at the engine's seeding refusal (the IllegalArgumentException the factory throws for a do result it has no generator for), over every analysis in the test module, with an unconditional entry and completion line per analysis so the counts are certified: 1616 analyses entered and 1616 completed, 120803 sources seeded, 310016 refusals, and 113 cases in which the factory returned null rather than throwing (the seeding path stores such a source anyway, and a probe on that path meets the null before it meets the exception). Joined by class against the 180 summary classes in tensorflow.xml whose method allocates a fresh Tensor and returns it: 26 refused classes allocate a fresh tensor. Twenty-three of those are Keras layer classes whose refused invoke is the layer call (__call__/call), unseeded by design and typed by the forward-result dataflow. Of the rest, conv2d (14 refusals) and conv3d (5) have their own engine-side handling. What is left is tensorflow/math/shape, with 3760 refusals, the most refused summary of any kind after user code bodies. One op, reached often.

At a subscript of it, read with a second probe that walks a function's IR value by value and prints whether each value has a dataflow node and whether its state is null, empty or populated (the harness's own dump omits empty states, so it cannot tell ⊥ from "no node"): in the two concrete propagate bodies of a graph neural network library's message-passing layers (a public project, the example here), v22 = tf.shape(node_embeddings) is in the flow graph with an empty state in every context (6 and 10), and so is v21 = v22[0], the nodes_num those bodies pass on. The receiver of the subscript is not ⊤ but ⊥, so the subscript pin's decline for an unranked receiver (#405) never has a member to decline on, and the subscript generator reads an empty receiver. A control in the same program: a num_nodes parameter that is genuinely not a tensor (len(features) at both call sites) reads empty in all 13 of its contexts, correctly.

Why A Generator Rather Than A Summary Change

The summary's own comment leaves the result "at ⊤ (no per-op generator wired up here)", and that is the intent the engine does not carry out: an allocation with no generator is refused, not seeded as ⊤. The result of tf.shape(x) is rank 1 and int32 statically, always. Its single extent is the rank of its input, so when the input's rank is known it is a concrete (r,), and only an unranked input degrades it to (Unresolved,). A Shape generator (input operand at position 0, input) gives that, and with a rank-1 receiver the subscript pin engages by its existing rule and [0] resolves to a rank-0 int32 scalar with no change to the subscript machinery. The registration for that change is wide: tf.shape appears wherever shape arithmetic does, so it wants the full-module value diff and node and edge counts, and the (r,)-when-rank-is-known half is the part most likely to move something unexpected.

What This Does Not Fix

The parameter that prompted the measurement belongs to a function the analysis never enters, because its class inherits it across a module boundary that falls to object (#571, narrowed there). A Shape generator moves nodes_num at the call sites and cannot move that parameter.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions