feat: make .* and ./ synonyms for tensor scaling - #24
Merged
Merged
Conversation
`AbstractTensor` defined no `Base.broadcastable`, so `weights .* ω` failed with a `MethodError` that gave no hint that `weights * ω` is the supported spelling — and our port of upstream's batch-scaling test had to drop the `np.multiply(weights, vecs)` arm that `__array_ufunc__` routes back to `Tensor.__mul__`. A tensor now carries its own `BroadcastStyle`, so it is never an array to the broadcast machinery: `copy` hands a dotted `*` or `/` straight back to the tensor algebra, and every other elementwise operation — meaningless on basis-dependent coefficients — throws an `ArgumentError` naming the supported spellings. Closes #19
wardjm
added a commit
that referenced
this pull request
Jul 12, 2026
Audited every API name and code block in the README against the package by executing them, rather than reading. The prose was accurate but had fallen behind three merged features and carried one broken link. - The install URL pointed at `wardjm/DiffusionGeometryJ.jl`; the repository is `wardjm/DiffusionGeometryJ` (no `.jl`), so `Pkg.add` as documented would have failed. - Batching went unmentioned entirely — no `batch_shape`, and no note that batch axes broadcast numpy-style from the right rather than by Julia's rule. That is a real trap when porting, and it was only recorded in the Conventions page. - `.*` and `./` (#24) and the accessors were undocumented. A numeric array scaling a tensor means batch-wise scalars, which is what makes `exp.(-evals) .* evecs` a spectral filter; that now appears where a reader will look for it. - The `show` methods added in c3bbd84 are shown, and the coefficients-not-values distinction that motivates `to_pointwise_basis` is stated in both the tensor section and Conventions. The Documentation section now says the guide pages' examples run in the suite too (true as of the previous commit) and links the Conventions and upstream-bugs pages. Everything else — the constructor table, the operator and Betti sections, the degree conventions, `hodge_decomposition`'s two return shapes — was checked against a live geometry and is correct as written.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #19.
AbstractTensordefined noBase.broadcastable, soweights .* ωfailed with aMethodErrorthat gave no hint thatweights * ωis the supported spelling. Our port of upstream'stest_spectrum_eigenvector_batch_scaling_with_numpyalso had to drop its third arm,np.multiply(weights, vecs), which__array_ufunc__routes back toTensor.__mul__.What this does
Of the three shapes the issue put up, this takes the custom
BroadcastStyleone. A tensor is never an array to the broadcast machinery: it carries its own style,instantiateskips the axis computation, andcopyhands a dotted*or/straight back to the tensor algebra.weights .* ωis exactlyweights * ω— a single batched tensor, never anArray{Form}(the divergence that made theRef(t)option unattractive).*and/accept: batch weights, a scalar, aScalarFunction, another tensor. Soa1 .* b1is the tensor product, just asa1 * b1is.@.flattens a chain into one n-ary call, so n-ary*and/are folded the way Julia associates them (@. w * X / 2).ω .+ 1,abs.(ω)) is meaningless on basis-dependent coefficients and now throws anArgumentErrornaming the supported spellings, instead of a bareMethodError.Tests
test_tensor_algebra.jlgains abroadcasting is a synonym for scalingtestset: the three scaling arms, scalar and function operands, tensor ⊙ tensor, nested and@.-flattened chains, and theArgumentErrorarms.test_pyclasses.jlrestores the droppednp.multiplyarm asweights .* vecs, so all three arms of the upstream test are now covered.Full suite passes.